Commit ab858e08 authored by Xavier Poinas's avatar Xavier Poinas

Merge remote-tracking branch 'upstream/master'

parents 0e21209b d0b9bf9c
...@@ -104,6 +104,17 @@ public void InsertGetUpdate() ...@@ -104,6 +104,17 @@ public void InsertGetUpdate()
} }
} }
public void InsertCheckKey()
{
using (var connection = GetOpenConnection())
{
connection.Get<IUser>(3).IsNull();
User user = new User { Name = "Adamb", Age = 10 };
int id = (int)connection.Insert(user);
user.Id.IsEqualTo(id);
}
}
public void BuilderSelectClause() public void BuilderSelectClause()
{ {
using (var connection = GetOpenConnection()) using (var connection = GetOpenConnection())
......
...@@ -255,6 +255,9 @@ private static string GetTableName(Type type) ...@@ -255,6 +255,9 @@ private static string GetTableName(Type type)
/// <returns>true if deleted, false if not found</returns> /// <returns>true if deleted, false if not found</returns>
public static bool Delete<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class public static bool Delete<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{ {
if (entityToDelete == null)
throw new ArgumentException("Cannot Delete null Object", "entityToDelete");
var type = typeof(T); var type = typeof(T);
var keyProperties = KeyPropertiesCache(type); var keyProperties = KeyPropertiesCache(type);
...@@ -486,7 +489,10 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -486,7 +489,10 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
//NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE //NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout); var r = connection.Query("select @@IDENTITY id", transaction: transaction, commandTimeout: commandTimeout);
return (int)r.First().id; int id = (int)r.First().id;
if (keyProperties.Any())
keyProperties.First().SetValue(entityToInsert, id, null);
return id;
} }
} }
...@@ -497,15 +503,22 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com ...@@ -497,15 +503,22 @@ public int Insert(IDbConnection connection, IDbTransaction transaction, int? com
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList);
// If no primary key then safe to assume a join table with not too much data to return
if (!keyProperties.Any())
sb.Append(" RETURNING *");
else
{
sb.Append(" RETURNING "); sb.Append(" RETURNING ");
bool first = true; bool first = true;
foreach(var property in keyProperties) foreach (var property in keyProperties)
{ {
if (!first) if (!first)
sb.Append(", "); sb.Append(", ");
first = false; first = false;
sb.Append(property.Name); sb.Append(property.Name);
} }
}
var results = connection.Query(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout); var results = connection.Query(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
// Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys // Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
<Compile Include="Database.cs" /> <Compile Include="Database.cs" />
<Compile Include="Snapshotter.cs" /> <Compile Include="Snapshotter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SqlCompactDatabase.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Dapper\Dapper.csproj"> <ProjectReference Include="..\Dapper\Dapper.csproj">
......
...@@ -26,9 +26,9 @@ public abstract class Database<TDatabase> : IDisposable where TDatabase : Databa ...@@ -26,9 +26,9 @@ public abstract class Database<TDatabase> : IDisposable where TDatabase : Databa
{ {
public class Table<T> public class Table<T>
{ {
Database<TDatabase> database; internal Database<TDatabase> database;
string tableName; internal string tableName;
string likelyTableName; internal string likelyTableName;
public Table(Database<TDatabase> database, string likelyTableName) public Table(Database<TDatabase> database, string likelyTableName)
{ {
...@@ -50,7 +50,7 @@ public string TableName ...@@ -50,7 +50,7 @@ public string TableName
/// </summary> /// </summary>
/// <param name="data">Either DynamicParameters or an anonymous type or concrete type</param> /// <param name="data">Either DynamicParameters or an anonymous type or concrete type</param>
/// <returns></returns> /// <returns></returns>
public int? Insert(dynamic data) public virtual int? Insert(dynamic data)
{ {
var o = (object)data; var o = (object)data;
List<string> paramNames = GetParamNames(o); List<string> paramNames = GetParamNames(o);
...@@ -114,7 +114,7 @@ public IEnumerable<T> All() ...@@ -114,7 +114,7 @@ public IEnumerable<T> All()
} }
static ConcurrentDictionary<Type, List<string>> paramNameCache = new ConcurrentDictionary<Type, List<string>>(); static ConcurrentDictionary<Type, List<string>> paramNameCache = new ConcurrentDictionary<Type, List<string>>();
private static List<string> GetParamNames(object o) internal static List<string> GetParamNames(object o)
{ {
if (o is DynamicParameters) if (o is DynamicParameters)
{ {
...@@ -147,18 +147,23 @@ public static TDatabase Init(DbConnection connection, int commandTimeout) ...@@ -147,18 +147,23 @@ public static TDatabase Init(DbConnection connection, int commandTimeout)
return db; return db;
} }
private static Action<Database<TDatabase>> tableConstructor; internal static Action<TDatabase> tableConstructor;
private void InitDatabase(DbConnection connection, int commandTimeout) internal void InitDatabase(DbConnection connection, int commandTimeout)
{ {
this.connection = connection; this.connection = connection;
this.commandTimeout = commandTimeout; this.commandTimeout = commandTimeout;
if (tableConstructor == null) if (tableConstructor == null)
{ {
tableConstructor = CreateTableConstructor(); tableConstructor = CreateTableConstructorForTable();
} }
tableConstructor(this); tableConstructor(this as TDatabase);
}
internal virtual Action<TDatabase> CreateTableConstructorForTable()
{
return CreateTableConstructor(typeof(Table<>));
} }
public void BeginTransaction(IsolationLevel isolation = IsolationLevel.ReadCommitted) public void BeginTransaction(IsolationLevel isolation = IsolationLevel.ReadCommitted)
...@@ -178,16 +183,16 @@ public void RollbackTransaction() ...@@ -178,16 +183,16 @@ public void RollbackTransaction()
transaction = null; transaction = null;
} }
protected Action<Database<TDatabase>> CreateTableConstructor() protected Action<TDatabase> CreateTableConstructor(Type tableType)
{ {
var dm = new DynamicMethod("ConstructInstances", null, new Type[] { typeof(Database<TDatabase>) }, true); var dm = new DynamicMethod("ConstructInstances", null, new Type[] { typeof(TDatabase) }, true);
var il = dm.GetILGenerator(); var il = dm.GetILGenerator();
var setters = GetType().GetProperties() var setters = GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Table<>)) .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == tableType)
.Select(p => Tuple.Create( .Select(p => Tuple.Create(
p.GetSetMethod(true), p.GetSetMethod(true),
p.PropertyType.GetConstructor(new Type[] { typeof(Database<TDatabase>), typeof(string) }), p.PropertyType.GetConstructor(new Type[] { typeof(TDatabase), typeof(string) }),
p.Name, p.Name,
p.DeclaringType p.DeclaringType
)); ));
...@@ -221,7 +226,7 @@ protected Action<Database<TDatabase>> CreateTableConstructor() ...@@ -221,7 +226,7 @@ protected Action<Database<TDatabase>> CreateTableConstructor()
} }
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
return (Action<Database<TDatabase>>)dm.CreateDelegate(typeof(Action<Database<TDatabase>>)); return (Action<TDatabase>)dm.CreateDelegate(typeof(Action<TDatabase>));
} }
static ConcurrentDictionary<Type, string> tableNameMap = new ConcurrentDictionary<Type, string>(); static ConcurrentDictionary<Type, string> tableNameMap = new ConcurrentDictionary<Type, string>();
......
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
namespace Dapper.Rainbow
{
public abstract class SqlCompactDatabase<TDatabase> : Database<TDatabase>, IDisposable where TDatabase : Database<TDatabase>, new()
{
public class SqlCompactTable<T> : Table<T>
{
public SqlCompactTable(Database<TDatabase> database, string likelyTableName)
: base(database, likelyTableName)
{
}
/// <summary>
/// Insert a row into the db
/// </summary>
/// <param name="data">Either DynamicParameters or an anonymous type or concrete type</param>
/// <returns></returns>
public override int? Insert(dynamic data)
{
var o = (object)data;
List<string> paramNames = GetParamNames(o);
paramNames.Remove("Id");
string cols = string.Join(",", paramNames);
string cols_params = string.Join(",", paramNames.Select(p => "@" + p));
var sql = "insert " + TableName + " (" + cols + ") values (" + cols_params + ")";
if (database.Execute(sql, o) != 1)
{
return null;
}
return (int)database.Query<decimal>("SELECT @@IDENTITY AS LastInsertedId").Single();
}
}
public static TDatabase Init(DbConnection connection)
{
TDatabase db = new TDatabase();
db.InitDatabase(connection, 0);
return db;
}
internal override Action<TDatabase> CreateTableConstructorForTable()
{
return CreateTableConstructor(typeof(SqlCompactTable<>));
}
}
}
...@@ -1145,6 +1145,15 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1145,6 +1145,15 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
var count = 0; var count = 0;
if (list != null) if (list != null)
{
if (FeatureSupport.Get(command.Connection).Arrays)
{
var arrayParm = command.CreateParameter();
arrayParm.Value = list;
arrayParm.ParameterName = namePrefix;
command.Parameters.Add(arrayParm);
}
else
{ {
bool isString = value is IEnumerable<string>; bool isString = value is IEnumerable<string>;
bool isDbString = value is IEnumerable<DbString>; bool isDbString = value is IEnumerable<DbString>;
...@@ -1157,7 +1166,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1157,7 +1166,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
if (isString) if (isString)
{ {
listParam.Size = 4000; listParam.Size = 4000;
if (item != null && ((string)item).Length > 4000) if (item != null && ((string) item).Length > 4000)
{ {
listParam.Size = -1; listParam.Size = -1;
} }
...@@ -1191,6 +1200,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -1191,6 +1200,7 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
}); });
} }
} }
}
} }
...@@ -2202,4 +2212,34 @@ public void AddParameter(IDbCommand command, string name) ...@@ -2202,4 +2212,34 @@ public void AddParameter(IDbCommand command, string name)
command.Parameters.Add(param); command.Parameters.Add(param);
} }
} }
/// <summary>
/// Handles variances in features per DBMS
/// </summary>
public class FeatureSupport
{
/// <summary>
/// Dictionary of supported features index by connection type name
/// </summary>
private static readonly Dictionary<string, FeatureSupport> FeatureList = new Dictionary<string, FeatureSupport>() {
{"sqlserverconnection", new FeatureSupport { Arrays = false}},
{"npgsqlconnection", new FeatureSupport {Arrays = true}}
};
/// <summary>
/// Gets the featureset based on the passed connection
/// </summary>
public static FeatureSupport Get(IDbConnection connection)
{
string name = connection.GetType().Name.ToLower();
FeatureSupport features;
return FeatureList.TryGetValue(name, out features) ? features : FeatureList.Values.First();
}
/// <summary>
/// True if the db supports array columns e.g. Postgresql
/// </summary>
public bool Arrays { get; set; }
}
} }
...@@ -59,12 +59,18 @@ ...@@ -59,12 +59,18 @@
<Reference Include="LinFu.DynamicProxy"> <Reference Include="LinFu.DynamicProxy">
<HintPath>NHibernate\LinFu.DynamicProxy.dll</HintPath> <HintPath>NHibernate\LinFu.DynamicProxy.dll</HintPath>
</Reference> </Reference>
<Reference Include="Mono.Security">
<HintPath>..\packages\Npgsql.2.0.11\lib\Net40\Mono.Security.dll</HintPath>
</Reference>
<Reference Include="NHibernate"> <Reference Include="NHibernate">
<HintPath>NHibernate\NHibernate.dll</HintPath> <HintPath>NHibernate\NHibernate.dll</HintPath>
</Reference> </Reference>
<Reference Include="NHibernate.ByteCode.LinFu"> <Reference Include="NHibernate.ByteCode.LinFu">
<HintPath>NHibernate\NHibernate.ByteCode.LinFu.dll</HintPath> <HintPath>NHibernate\NHibernate.ByteCode.LinFu.dll</HintPath>
</Reference> </Reference>
<Reference Include="Npgsql">
<HintPath>..\packages\Npgsql.2.0.11\lib\Net40\Npgsql.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Common, Version=1.0.4110.36238, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="ServiceStack.Common, Version=1.0.4110.36238, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>OrmLite\ServiceStack.Common.dll</HintPath> <HintPath>OrmLite\ServiceStack.Common.dll</HintPath>
......
using System; //#define POSTGRESQL // uncomment to run postgres tests
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq; using System.Linq;
...@@ -8,6 +9,9 @@ ...@@ -8,6 +9,9 @@
using System.Data; using System.Data;
using System.Collections; using System.Collections;
using System.Reflection; using System.Reflection;
#if POSTGRESQL
using Npgsql;
#endif
namespace SqlMapper namespace SqlMapper
{ {
...@@ -1388,5 +1392,46 @@ public enum ShortEnum : short ...@@ -1388,5 +1392,46 @@ public enum ShortEnum : short
{ {
Zero = 0, One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6 Zero = 0, One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6
} }
#if POSTGRESQL
class Cat
{
public int Id { get; set; }
public string Breed { get; set; }
public string Name { get; set; }
}
Cat[] Cats = {
new Cat() { Breed = "Abyssinian", Name="KACTUS"},
new Cat() { Breed = "Aegean cat", Name="KADAFFI"},
new Cat() { Breed = "American Bobtail", Name="KANJI"},
new Cat() { Breed = "Balinese", Name="MACARONI"},
new Cat() { Breed = "Bombay", Name="MACAULAY"},
new Cat() { Breed = "Burmese", Name="MACBETH"},
new Cat() { Breed = "Chartreux", Name="MACGYVER"},
new Cat() { Breed = "German Rex", Name="MACKENZIE"},
new Cat() { Breed = "Javanese", Name="MADISON"},
new Cat() { Breed = "Persian", Name="MAGNA"}
};
public void TestPostresqlArrayParameters()
{
using (var conn = new NpgsqlConnection("Server=localhost;Port=5432;User Id=dappertest;Password=dapperpass;Database=dappertest;Encoding=UNICODE"))
{
conn.Open();
IDbTransaction transaction = conn.BeginTransaction();
conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);");
conn.Execute("insert tcat(breed, name) values(:breed, :name) ", Cats);
var r = conn.Query<Cat>("select * from tcat where id=any(:catids)", new { catids = new[] { 1, 3, 5 } });
r.Count().IsEqualTo(3);
r.Count(c => c.Id == 1).IsEqualTo(1);
r.Count(c => c.Id == 3).IsEqualTo(1);
r.Count(c => c.Id == 5).IsEqualTo(1);
transaction.Rollback();
}
}
#endif
} }
} }
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="SqlServerCompact" version="4.0.8482.1" />
<package id="FSPowerPack.Community" version="2.0.0.0" /> <package id="FSPowerPack.Community" version="2.0.0.0" />
<package id="Npgsql" version="2.0.11" />
<package id="SqlServerCompact" version="4.0.8482.1" />
</packages> </packages>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment