Commit 885a8d46 authored by Marc Gravell's avatar Marc Gravell

Provide support for OleDB / anonymous sql parameters

parent 8f017a25
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NuGet.CommandLine" version="2.0.40001" />
<package id="NuGet.CommandLine" version="2.5.0" />
<package id="NuGet.CommandLine" version="2.0.40001" />
</packages>
\ No newline at end of file
......@@ -264,7 +264,7 @@ public static void PurgeQueryCache()
{
lock (_queryCache)
{
_queryCache.Clear();
_queryCache.Clear();
}
OnQueryCachePurged();
}
......@@ -656,7 +656,7 @@ public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object
/// <summary>
/// Execute a command that returns multiple result sets, and access each in turn
/// </summary>
public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)
public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)
{
return QueryMultiple(cnn, sql, param, transaction, null, null);
}
......@@ -664,7 +664,7 @@ public static GridReader QueryMultiple(this IDbConnection cnn, string sql, objec
/// <summary>
/// Execute a command that returns multiple result sets, and access each in turn
/// </summary>
public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, CommandType commandType)
public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param, CommandType commandType)
{
return QueryMultiple(cnn, sql, param, null, null, commandType);
}
......@@ -683,7 +683,7 @@ public static GridReader QueryMultiple(this IDbConnection cnn, string sql, objec
/// <returns>Number of rows affected</returns>
public static int Execute(
#if CSHARP30
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType
#else
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
#endif
......@@ -741,35 +741,40 @@ public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, dyn
/// <summary>
/// Return a list of dynamic objects, reader is closed after the call
/// </summary>
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param) {
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param)
{
return Query(cnn, sql, param, null, true, null, null);
}
/// <summary>
/// Return a list of dynamic objects, reader is closed after the call
/// </summary>
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction) {
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction)
{
return Query(cnn, sql, param, transaction, true, null, null);
}
/// <summary>
/// Return a list of dynamic objects, reader is closed after the call
/// </summary>
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, CommandType? commandType) {
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, CommandType? commandType)
{
return Query(cnn, sql, param, null, true, null, commandType);
}
/// <summary>
/// Return a list of dynamic objects, reader is closed after the call
/// </summary>
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType? commandType) {
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, CommandType? commandType)
{
return Query(cnn, sql, param, transaction, true, null, commandType);
}
/// <summary>
/// Return a list of dynamic objects, reader is closed after the call
/// </summary>
public static IEnumerable<IDictionary<string,object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType) {
public static IEnumerable<IDictionary<string, object>> Query(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType)
{
return Query<IDictionary<string, object>>(cnn, sql, param, transaction, buffered, commandTimeout, commandType);
}
#endif
......@@ -783,7 +788,7 @@ public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, dyn
/// </returns>
public static IEnumerable<T> Query<T>(
#if CSHARP30
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType
#else
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null
#endif
......@@ -797,8 +802,8 @@ public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, dyn
/// Execute a command that returns multiple result sets, and access each in turn
/// </summary>
public static GridReader QueryMultiple(
#if CSHARP30
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType
#if CSHARP30
this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType
#else
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null
#endif
......@@ -908,8 +913,8 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
/// <param name="commandType">Is it a stored proc or a batch?</param>
/// <returns></returns>
public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(
#if CSHARP30
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType
#if CSHARP30
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType
#else
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
#endif
......@@ -937,7 +942,7 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
/// <returns></returns>
public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(
#if CSHARP30
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType
#else
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
#endif
......@@ -966,7 +971,7 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
/// <returns></returns>
public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(
#if CSHARP30
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType
#else
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null
#endif
......@@ -1064,7 +1069,7 @@ partial class DontMap { }
return buffered ? results.ToList() : results;
}
static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, string sql, object map, object param, IDbTransaction transaction, string splitOn, int? commandTimeout, CommandType? commandType, IDataReader reader, Identity identity)
{
identity = identity ?? new Identity(sql, commandType, cnn, typeof(TFirst), (object)param == null ? null : ((object)param).GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) });
......@@ -1247,7 +1252,7 @@ private static CacheInfo GetCacheInfo(Identity identity)
#endif
else
{
info.ParamReader = CreateParamInfoGenerator(identity, false);
info.ParamReader = CreateParamInfoGenerator(identity, false, true);
}
}
SetQueryCache(identity, info);
......@@ -1265,7 +1270,7 @@ private static CacheInfo GetCacheInfo(Identity identity)
return GetDapperRowDeserializer(reader, startBound, length, returnNullIfFirstMissing);
}
#else
if(type.IsAssignableFrom(typeof(Dictionary<string,object>)))
if (type.IsAssignableFrom(typeof(Dictionary<string, object>)))
{
return GetDictionaryDeserializer(reader, startBound, length, returnNullIfFirstMissing);
}
......@@ -1497,7 +1502,7 @@ IEnumerator IEnumerable.GetEnumerator()
return GetEnumerator();
}
#region Implementation of ICollection<KeyValuePair<string,object>>
#region Implementation of ICollection<KeyValuePair<string,object>>
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
{
......@@ -1538,7 +1543,7 @@ IEnumerator IEnumerable.GetEnumerator()
#endregion
#region Implementation of IDictionary<string,object>
#region Implementation of IDictionary<string,object>
bool IDictionary<string, object>.ContainsKey(string key)
{
......@@ -1831,13 +1836,22 @@ private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyIn
return parameters.Where(p => Regex.IsMatch(sql, @"[?@:]" + p.Name + "([^a-zA-Z0-9_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline));
}
// look for ? / @ / : *by itself*
static readonly Regex smellsLikeOleDb = new Regex(@"(?<![a-zA-Z0-9_])[?@:](?![a-zA-Z0-9_])", RegexOptions.Compiled);
/// <summary>
/// Internal use only
/// </summary>
public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates)
public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused)
{
Type type = identity.parametersType;
bool filterParams = identity.commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text;
bool filterParams = false;
if (removeUnused && identity.commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text)
{
filterParams = !smellsLikeOleDb.IsMatch(identity.sql);
}
var dm = new DynamicMethod(string.Format("ParamInfo{0}", Guid.NewGuid()), null, new[] { typeof(IDbCommand), typeof(object) }, type, true);
var il = dm.GetILGenerator();
......@@ -1851,11 +1865,63 @@ private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyIn
il.Emit(OpCodes.Ldarg_0); // stack is now [command]
il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetProperty("Parameters").GetGetMethod(), null); // stack is now [parameters]
IEnumerable<PropertyInfo> props = type.GetProperties().Where(p => p.GetIndexParameters().Length == 0).OrderBy(p => p.Name);
var propsArr = type.GetProperties().Where(p => p.GetIndexParameters().Length == 0).ToArray();
var ctors = type.GetConstructors();
ParameterInfo[] ctorParams;
IEnumerable<PropertyInfo> props = null;
// try to detect tuple patterns, e.g. anon-types, and use that to choose the order
// otherwise: alphabetical
if (ctors.Length == 1 && propsArr.Length == (ctorParams = ctors[0].GetParameters()).Length)
{
// check if reflection was kind enough to put everything in the right order for us
bool ok = true;
for (int i = 0; i < propsArr.Length; i++)
{
if (!string.Equals(propsArr[i].Name, ctorParams[i].Name, StringComparison.InvariantCultureIgnoreCase))
{
ok = false;
break;
}
}
if(ok)
{
// pre-sorted; the reflection gods have smiled upon us
props = propsArr;
}
else { // might still all be accounted for; check the hard way
var positionByName = new Dictionary<string,int>(StringComparer.InvariantCultureIgnoreCase);
foreach(var param in ctorParams)
{
positionByName[param.Name] = param.Position;
}
if (positionByName.Count == propsArr.Length)
{
int[] positions = new int[propsArr.Length];
ok = true;
for (int i = 0; i < propsArr.Length; i++)
{
int pos;
if (!positionByName.TryGetValue(propsArr[i].Name, out pos))
{
ok = false;
break;
}
positions[i] = pos;
}
if (ok)
{
Array.Sort(positions, propsArr);
props = propsArr;
}
}
}
}
if(props == null) props = propsArr.OrderBy(x => x.Name);
if (filterParams)
{
props = FilterParameters(props, identity.sql);
}
foreach (var prop in props)
{
if (filterParams)
......@@ -2154,7 +2220,7 @@ public static void SetTypeMap(Type type, ITypeMap map)
/// <returns></returns>
public static Func<IDataReader, object> GetTypeDeserializer(
#if CSHARP30
Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing
Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing
#else
Type type, IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false
#endif
......@@ -2489,7 +2555,7 @@ static MethodInfo GetOperator(Type from, Type to)
?? ResolveOperator(toMethods = to.GetMethods(BindingFlags.Static | BindingFlags.Public), from, to, "op_Implicit")
?? ResolveOperator(fromMethods, from, to, "op_Explicit")
?? ResolveOperator(toMethods, from, to, "op_Explicit");
}
static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type to, string name)
{
......@@ -2730,7 +2796,7 @@ public IEnumerable<T> Read<T>(bool buffered = true)
/// <summary>
/// Read multiple objects from a single recordset on the grid
/// </summary>
#if CSHARP30
#if CSHARP30
public IEnumerable<TReturn> Read<TFirst, TSecond, TReturn>(Func<TFirst, TSecond, TReturn> func, string splitOn, bool buffered)
#else
public IEnumerable<TReturn> Read<TFirst, TSecond, TReturn>(Func<TFirst, TSecond, TReturn> func, string splitOn = "id", bool buffered = true)
......@@ -2752,7 +2818,7 @@ public IEnumerable<T> Read<T>(bool buffered = true)
/// <summary>
/// Read multiple objects from a single recordset on the grid
/// </summary>
#if CSHARP30
#if CSHARP30
public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TReturn>(Func<TFirst, TSecond, TThird, TReturn> func, string splitOn, bool buffered)
#else
public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TReturn>(Func<TFirst, TSecond, TThird, TReturn> func, string splitOn = "id", bool buffered = true)
......@@ -2775,7 +2841,7 @@ public IEnumerable<T> Read<T>(bool buffered = true)
/// <summary>
/// Read multiple objects from a single record set on the grid
/// </summary>
#if CSHARP30
#if CSHARP30
public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TReturn> func, string splitOn, bool buffered)
#else
public IEnumerable<TReturn> Read<TFirst, TSecond, TThird, TFourth, TReturn>(Func<TFirst, TSecond, TThird, TFourth, TReturn> func, string splitOn = "id", bool buffered = true)
......@@ -2896,7 +2962,10 @@ partial class ParamInfo
/// <summary>
/// construct a dynamic parameter bag
/// </summary>
public DynamicParameters() { }
public DynamicParameters()
{
RemoveUnused = true;
}
/// <summary>
/// construct a dynamic parameter bag
......@@ -2904,6 +2973,7 @@ partial class ParamInfo
/// <param name="template">can be an anonymous type or a DynamicParameters bag</param>
public DynamicParameters(object template)
{
RemoveUnused = true;
AddDynamicParams(template);
}
......@@ -2914,7 +2984,7 @@ public DynamicParameters(object template)
/// <param name="param"></param>
public void AddDynamicParams(
#if CSHARP30
object param
object param
#else
dynamic param
#endif
......@@ -2976,7 +3046,7 @@ dynamic param
/// <param name="size"></param>
public void Add(
#if CSHARP30
string name, object value, DbType? dbType, ParameterDirection? direction, int? size
string name, object value, DbType? dbType, ParameterDirection? direction, int? size
#else
string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null
#endif
......@@ -3005,6 +3075,11 @@ void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Id
AddParameters(command, identity);
}
/// <summary>
/// If true, the command-text is inspected and only values that are clearly used are included on the connection
/// </summary>
public bool RemoveUnused { get; set; }
/// <summary>
/// Add all the parameters needed to the command just before it executes
/// </summary>
......@@ -3023,7 +3098,7 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
if (!paramReaderCache.TryGetValue(newIdent, out appender))
{
appender = SqlMapper.CreateParamInfoGenerator(newIdent, true);
appender = SqlMapper.CreateParamInfoGenerator(newIdent, true, RemoveUnused);
paramReaderCache[newIdent] = appender;
}
}
......
......@@ -78,7 +78,7 @@ internal class SomaConfig : Soma.Core.MsSqlConfig
{
public override string ConnectionString
{
get { return Program.connectionString; }
get { return Program.ConnectionString; }
}
public override void Log(Soma.Core.PreparedStatement preparedStatement)
......@@ -134,17 +134,17 @@ public void Run(int iterations)
var mapperConnection3 = Program.GetOpenConnection();
tests.Add(id => mapperConnection2.Get<Post>(id), "Dapper.Cotrib");
var massiveModel = new DynamicModel(Program.connectionString);
var massiveModel = new DynamicModel(Program.ConnectionString);
var massiveConnection = Program.GetOpenConnection();
tests.Add(id => massiveModel.Query("select * from Posts where Id = @0", massiveConnection, id).First(), "Dynamic Massive ORM Query");
// PetaPoco test with all default options
var petapoco = new PetaPoco.Database(Program.connectionString, "System.Data.SqlClient");
var petapoco = new PetaPoco.Database(Program.ConnectionString, "System.Data.SqlClient");
petapoco.OpenSharedConnection();
tests.Add(id => petapoco.Fetch<Post>("SELECT * from Posts where Id=@0", id), "PetaPoco (Normal)");
// PetaPoco with some "smart" functionality disabled
var petapocoFast = new PetaPoco.Database(Program.connectionString, "System.Data.SqlClient");
var petapocoFast = new PetaPoco.Database(Program.ConnectionString, "System.Data.SqlClient");
petapocoFast.OpenSharedConnection();
petapocoFast.EnableAutoSelect = false;
petapocoFast.EnableNamedParams = false;
......@@ -188,7 +188,7 @@ public void Run(int iterations)
tests.Add(id => db1.SetCommand("select * from Posts where Id = @id", db1.Parameter("id", id)).ExecuteList<Post>(), "BLToolkit");
// Simple.Data
var sdb = Simple.Data.Database.OpenConnection(Program.connectionString);
var sdb = Simple.Data.Database.OpenConnection(Program.ConnectionString);
tests.Add(id => sdb.Posts.FindById(id), "Simple.Data");
// Soma
......
......@@ -28,11 +28,12 @@ class Post
class Program
{
public static readonly string connectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=True";
public const string ConnectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=True",
OleDbConnectionString = "Provider=SQLOLEDB;Data Source=.;Initial Catalog=tempdb;Integrated Security=SSPI";
public static SqlConnection GetOpenConnection()
{
var connection = new SqlConnection(connectionString);
var connection = new SqlConnection(ConnectionString);
connection.Open();
return connection;
}
......
......@@ -67,7 +67,7 @@ public PostWithConstructor(int id, int ownerid, string content)
}
public void TestMultiMapWithConstructor()
{
{
var createSql = @"
create table #Users (Id int, Name varchar(20))
create table #Posts (Id int, OwnerId int, Content varchar(20))
......@@ -79,20 +79,25 @@ public void TestMultiMapWithConstructor()
insert #Posts values(2, 99, 'Sams Post2')
insert #Posts values(3, null, 'no ones post')";
connection.Execute(createSql);
string sql = @"select * from #Posts p
try
{
string sql = @"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
PostWithConstructor[] data = connection.Query<PostWithConstructor, UserWithConstructor, PostWithConstructor>(sql, (post, user) => { post.Owner = user; return post;}).ToArray();
var p = data.First();
p.FullContent.IsEqualTo("Sams Post1");
p.Ident.IsEqualTo(1);
p.Owner.FullName.IsEqualTo("Sam");
p.Owner.Ident.IsEqualTo(99);
PostWithConstructor[] data = connection.Query<PostWithConstructor, UserWithConstructor, PostWithConstructor>(sql, (post, user) => { post.Owner = user; return post; }).ToArray();
var p = data.First();
data[2].Owner.IsNull();
p.FullContent.IsEqualTo("Sams Post1");
p.Ident.IsEqualTo(1);
p.Owner.FullName.IsEqualTo("Sam");
p.Owner.Ident.IsEqualTo(99);
connection.Execute("drop table #Users drop table #Posts");
data[2].Owner.IsNull();
}
finally
{
connection.Execute("drop table #Users drop table #Posts");
}
}
......@@ -159,7 +164,7 @@ public NoDefaultConstructor(int a1, int? b1, float f1, string s1, Guid G1)
public void TestNoDefaultConstructor()
{
var guid = Guid.NewGuid();
NoDefaultConstructor nodef = connection.Query<NoDefaultConstructor>("select CAST(NULL AS integer) A1, CAST(NULL AS integer) b1, CAST(NULL AS real) f1, 'Dapper' s1, G1 = @id", new { Id = guid }).First();
NoDefaultConstructor nodef = connection.Query<NoDefaultConstructor>("select CAST(NULL AS integer) A1, CAST(NULL AS integer) b1, CAST(NULL AS real) f1, 'Dapper' s1, G1 = @id", new { id = guid }).First();
nodef.A.IsEqualTo(0);
nodef.B.IsEqualTo(null);
nodef.F.IsEqualTo(0);
......@@ -231,7 +236,7 @@ public void TestNoDefaultConstructorBinary()
}
// http://stackoverflow.com/q/8593871
public void TestAbstractInheritance()
public void TestAbstractInheritance()
{
var order = connection.Query<AbstractInheritance.ConcreteOrder>("select 1 Internal,2 Protected,3 [Public],4 Concrete").First();
......@@ -279,7 +284,7 @@ public enum TrapEnum : int
#pragma warning restore 0649
public int Age { get; set; }
public TrapEnum Trap { get; set; }
}
public void TestStructs()
......@@ -315,35 +320,46 @@ public void PassInEmptyIntArray()
public void TestSchemaChanged()
{
connection.Execute("create table #dog(Age int, Name nvarchar(max)) insert #dog values(1, 'Alf')");
var d = connection.Query<Dog>("select * from #dog").Single();
d.Name.IsEqualTo("Alf");
d.Age.IsEqualTo(1);
connection.Execute("alter table #dog drop column Name");
d = connection.Query<Dog>("select * from #dog").Single();
d.Name.IsNull();
d.Age.IsEqualTo(1);
connection.Execute("drop table #dog");
try
{
var d = connection.Query<Dog>("select * from #dog").Single();
d.Name.IsEqualTo("Alf");
d.Age.IsEqualTo(1);
connection.Execute("alter table #dog drop column Name");
d = connection.Query<Dog>("select * from #dog").Single();
d.Name.IsNull();
d.Age.IsEqualTo(1);
}
finally
{
connection.Execute("drop table #dog");
}
}
public void TestSchemaChangedMultiMap()
{
connection.Execute("create table #dog(Age int, Name nvarchar(max)) insert #dog values(1, 'Alf')");
var tuple = connection.Query<Dog, Dog, Tuple<Dog, Dog>>("select * from #dog d1 join #dog d2 on 1=1", (d1, d2) => Tuple.Create(d1, d2), splitOn: "Age").Single();
tuple.Item1.Name.IsEqualTo("Alf");
tuple.Item1.Age.IsEqualTo(1);
tuple.Item2.Name.IsEqualTo("Alf");
tuple.Item2.Age.IsEqualTo(1);
try
{
var tuple = connection.Query<Dog, Dog, Tuple<Dog, Dog>>("select * from #dog d1 join #dog d2 on 1=1", (d1, d2) => Tuple.Create(d1, d2), splitOn: "Age").Single();
connection.Execute("alter table #dog drop column Name");
tuple = connection.Query<Dog, Dog, Tuple<Dog, Dog>>("select * from #dog d1 join #dog d2 on 1=1", (d1, d2) => Tuple.Create(d1, d2), splitOn: "Age").Single();
tuple.Item1.Name.IsEqualTo("Alf");
tuple.Item1.Age.IsEqualTo(1);
tuple.Item2.Name.IsEqualTo("Alf");
tuple.Item2.Age.IsEqualTo(1);
tuple.Item1.Name.IsNull();
tuple.Item1.Age.IsEqualTo(1);
tuple.Item2.Name.IsNull();
tuple.Item2.Age.IsEqualTo(1);
connection.Execute("alter table #dog drop column Name");
tuple = connection.Query<Dog, Dog, Tuple<Dog, Dog>>("select * from #dog d1 join #dog d2 on 1=1", (d1, d2) => Tuple.Create(d1, d2), splitOn: "Age").Single();
connection.Execute("drop table #dog");
tuple.Item1.Name.IsNull();
tuple.Item1.Age.IsEqualTo(1);
tuple.Item2.Name.IsNull();
tuple.Item2.Age.IsEqualTo(1);
}
finally
{
connection.Execute("drop table #dog");
}
}
public void TestReadMultipleIntegersWithSplitOnAny()
......@@ -404,7 +420,7 @@ public void CheckComplexConcat()
string term = "F"; // the term the user searched for
connection.Execute(@"create table #users16726709 (first_name varchar(200), last_name varchar(200))
insert #users16726709 values ('Fred','Bloggs') insert #users16726709 values ('Tony','Farcus') insert #users16726709 values ('Albert','Tenof')");
insert #users16726709 values ('Fred','Bloggs') insert #users16726709 values ('Tony','Farcus') insert #users16726709 values ('Albert','TenoF')");
// Using Dapper
connection.Query(end_wildcard, new { search_term = term }).Count().IsEqualTo(2);
......@@ -462,7 +478,7 @@ public class Dog
public void TestExtraFields()
{
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select '' as Extra, 1 as Age, 0.1 as Name1 , Id = @id", new { Id = guid });
var dog = connection.Query<Dog>("select '' as Extra, 1 as Age, 0.1 as Name1 , Id = @id", new { id = guid });
dog.Count()
.IsEqualTo(1);
......@@ -474,6 +490,20 @@ public void TestExtraFields()
.IsEqualTo(guid);
}
// see http://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?",
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
public void TestStrongType()
{
......@@ -542,10 +572,17 @@ public void TestExecuteCommandWithHybridParameters()
public void TestExecuteMultipleCommand()
{
connection.Execute("create table #t(i int)");
int tally = connection.Execute(@"insert #t (i) values(@a)", new[] { new { a = 1 }, new { a = 2 }, new { a = 3 }, new { a = 4 } });
int sum = connection.Query<int>("select sum(i) from #t drop table #t").First();
tally.IsEqualTo(4);
sum.IsEqualTo(10);
try
{
int tally = connection.Execute(@"insert #t (i) values(@a)", new[] { new { a = 1 }, new { a = 2 }, new { a = 3 }, new { a = 4 } });
int sum = connection.Query<int>("select sum(i) from #t").First();
tally.IsEqualTo(4);
sum.IsEqualTo(10);
}
finally
{
connection.Execute("drop table #t");
}
}
class Student
......@@ -557,14 +594,21 @@ class Student
public void TestExecuteMultipleCommandStrongType()
{
connection.Execute("create table #t(Name nvarchar(max), Age int)");
int tally = connection.Execute(@"insert #t (Name,Age) values(@Name, @Age)", new List<Student>
try
{
int tally = connection.Execute(@"insert #t (Name,Age) values(@Name, @Age)", new List<Student>
{
new Student{Age = 1, Name = "sam"},
new Student{Age = 2, Name = "bob"}
});
int sum = connection.Query<int>("select sum(Age) from #t drop table #t").First();
tally.IsEqualTo(2);
sum.IsEqualTo(3);
int sum = connection.Query<int>("select sum(Age) from #t").First();
tally.IsEqualTo(2);
sum.IsEqualTo(3);
}
finally
{
connection.Execute("drop table #t");
}
}
public void TestExecuteMultipleCommandObjectArray()
......@@ -591,7 +635,7 @@ class TestObj
public int _priv;
private int Priv { set { _priv = value; } }
private int PrivGet { get { return _priv;} }
private int PrivGet { get { return _priv; } }
}
public void TestSetInternal()
......@@ -608,7 +652,7 @@ public void TestSetPrivate()
public void TestExpandWithNullableFields()
{
var row = connection.Query("select null A, 2 B").Single();
((int?)row.A)
.IsNull();
......@@ -712,23 +756,27 @@ public void TestMultiMap()
insert #Posts values(3, null, 'no ones post')
";
connection.Execute(createSql);
var sql =
@"select * from #Posts p
try
{
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }).ToList();
var p = data.First();
p.Content.IsEqualTo("Sams Post1");
p.Id.IsEqualTo(1);
p.Owner.Name.IsEqualTo("Sam");
p.Owner.Id.IsEqualTo(99);
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }).ToList();
var p = data.First();
data[2].Owner.IsNull();
p.Content.IsEqualTo("Sams Post1");
p.Id.IsEqualTo(1);
p.Owner.Name.IsEqualTo("Sam");
p.Owner.Id.IsEqualTo(99);
connection.Execute("drop table #Users drop table #Posts");
data[2].Owner.IsNull();
}
finally
{
connection.Execute("drop table #Users drop table #Posts");
}
}
......@@ -807,7 +855,7 @@ public void TestQueryMultipleNonBufferedIncorrectOrder()
{
// that's expected
}
}
}
public void TestQueryMultipleNonBufferedCcorrectOrder()
......@@ -1592,26 +1640,30 @@ public void TestMultiMapThreeTypesWithGridReader()
insert #Comments values(1, 1, 'Comment 1')";
connection.Execute(createSql);
var sql = @"SELECT p.* FROM #Posts p
try
{
var sql = @"SELECT p.* FROM #Posts p
select p.*, u.Id, u.Name + '0' Name, c.Id, c.CommentData from #Posts p
left join #Users u on u.Id = p.OwnerId
left join #Comments c on c.postId = p.Id
left join #Comments c on c.PostId = p.Id
where p.Id = 1
Order by p.Id";
var grid = connection.QueryMultiple(sql);
var post1 = grid.Read<Post>().ToList();
var grid = connection.QueryMultiple(sql);
var post2 = grid.Read<Post, User, Comment, Post>((post, user, comment) => { post.Owner = user; post.Comment = comment; return post; }).SingleOrDefault();
var post1 = grid.Read<Post>().ToList();
post2.Comment.Id.IsEqualTo(1);
post2.Owner.Id.IsEqualTo(99);
var post2 = grid.Read<Post, User, Comment, Post>((post, user, comment) => { post.Owner = user; post.Comment = comment; return post; }).SingleOrDefault();
post2.Comment.Id.IsEqualTo(1);
post2.Owner.Id.IsEqualTo(99);
connection.Execute("drop table #Users drop table #Posts drop table #Comments");
}
finally
{
connection.Execute("drop table #Users drop table #Posts drop table #Comments");
}
}
public class DbParams : Dapper.SqlMapper.IDynamicParameters, IEnumerable<IDbDataParameter>
......@@ -1656,24 +1708,28 @@ public void TestReadDynamicWithGridReader()
insert #Posts values(1, 99, 'Sams Post1')
insert #Posts values(2, 99, 'Sams Post2')
insert #Posts values(3, null, 'no ones post')";
try
{
connection.Execute(createSql);
connection.Execute(createSql);
var sql = @"SELECT * FROM #Users ORDER BY Id
var sql = @"SELECT * FROM #Users ORDER BY Id
SELECT * FROM #Posts ORDER BY Id DESC";
var grid = connection.QueryMultiple(sql);
var users = grid.Read().ToList();
var posts = grid.Read().ToList();
var grid = connection.QueryMultiple(sql);
users.Count.IsEqualTo(2);
posts.Count.IsEqualTo(3);
var users = grid.Read().ToList();
var posts = grid.Read().ToList();
((int)users.First().Id).IsEqualTo(2);
((int)posts.First().Id).IsEqualTo(3);
users.Count.IsEqualTo(2);
posts.Count.IsEqualTo(3);
connection.Execute("drop table #Users drop table #Posts");
((int)users.First().Id).IsEqualTo(2);
((int)posts.First().Id).IsEqualTo(3);
}
finally
{
connection.Execute("drop table #Users drop table #Posts");
}
}
public void TestDynamicParamNullSupport()
......@@ -2056,7 +2112,7 @@ public void TestReaderWhenResultsChange()
{
try
{
connection.Execute("create table #ResultsChange (X int);create table #ResultsChange2 (Y int);insert #ResultsChange (X) values(1);insert #ResultsChange2 (Y) values(1);");
var obj1 = connection.Query<ResultsChangeType>("select * from #ResultsChange").Single();
......@@ -2081,7 +2137,8 @@ public void TestReaderWhenResultsChange()
obj4.X.IsEqualTo(1);
obj4.Y.IsEqualTo(1);
obj4.Z.IsEqualTo(2);
} finally
}
finally
{
connection.Execute("drop table #ResultsChange;drop table #ResultsChange2;");
}
......@@ -2101,7 +2158,7 @@ public void TestCustomTypeMap()
item.B.IsEqualTo("BVal");
// custom mapping
var map = new CustomPropertyTypeMap(typeof(TypeWithMapping),
var map = new CustomPropertyTypeMap(typeof(TypeWithMapping),
(type, columnName) => type.GetProperties().Where(prop => prop.GetCustomAttributes(false).OfType<DescriptionAttribute>().Any(attr => attr.Description == columnName)).FirstOrDefault());
Dapper.SqlMapper.SetTypeMap(typeof(TypeWithMapping), map);
......@@ -2132,7 +2189,7 @@ public class WrongTypes
public long C { get; set; }
public bool D { get; set; }
}
public void TestWrongTypes_WithRightTypes()
{
var item = connection.Query<WrongTypes>("select 1 as A, cast(2.0 as float) as B, cast(3 as bigint) as C, cast(1 as bit) as D").Single();
......@@ -2141,7 +2198,7 @@ public void TestWrongTypes_WithRightTypes()
item.C.Equals(3L);
item.D.Equals(true);
}
public void TestWrongTypes_WithWrongTypes()
{
var item = connection.Query<WrongTypes>("select cast(1.0 as float) as A, 2 as B, 3 as C, cast(1 as bigint) as D").Single();
......@@ -2193,14 +2250,14 @@ public void Issue_40_AutomaticBoolConversion()
public class Issue40_User
{
public Issue40_User()
{
Email = Password = String.Empty;
}
public int UserID { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public bool Active { get; set; }
public Issue40_User()
{
Email = Password = String.Empty;
}
public int UserID { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public bool Active { get; set; }
}
SqlConnection GetClosedConnection()
......@@ -2324,11 +2381,13 @@ public void TestMultiSelectWithSomeEmptyGrids()
var two = reader.Read<int>().ToArray();
var three = reader.Read<int>().ToArray();
var four = reader.Read<int>().ToArray();
try { // only returned four grids; expect a fifth read to fail
try
{ // only returned four grids; expect a fifth read to fail
reader.Read<int>();
throw new InvalidOperationException("this should not have worked!");
}
catch (ObjectDisposedException ex) { // expected; success
catch (ObjectDisposedException ex)
{ // expected; success
ex.Message.IsEqualTo("The reader has been disposed; this can happen after all data has been consumed\r\nObject name: 'Dapper.SqlMapper+GridReader'.");
}
......@@ -2345,7 +2404,7 @@ public void TestDynamicMutation()
{
var obj = connection.Query("select 1 as [a], 2 as [b], 3 as [c]").Single();
((int)obj.a).IsEqualTo(1);
IDictionary<string,object> dict = obj;
IDictionary<string, object> dict = obj;
Assert.Equals(3, dict.Count);
Assert.IsTrue(dict.Remove("a"));
Assert.IsFalse(dict.Remove("d"));
......@@ -2501,30 +2560,30 @@ public void Open()
}
}
public void TestDapperTableMetadataRetrieval()
{
// Test for a bug found in CS 51509960 where the following sequence would result in an InvalidOperationException being
// thrown due to an attempt to access a disposed of DataReader:
//
// - Perform a dynamic query that yields no results
// - Add data to the source of that query
// - Perform a the same query again
connection.Execute("CREATE TABLE #sut (value varchar(10) NOT NULL PRIMARY KEY)");
connection.Query("SELECT value FROM #sut").IsSequenceEqualTo(Enumerable.Empty<dynamic>());
connection.Execute("INSERT INTO #sut (value) VALUES ('test')").IsEqualTo(1);
var result = connection.Query("SELECT value FROM #sut");
var first = result.First();
((string)first.value).IsEqualTo("test");
}
public void TestDapperTableMetadataRetrieval()
{
// Test for a bug found in CS 51509960 where the following sequence would result in an InvalidOperationException being
// thrown due to an attempt to access a disposed of DataReader:
//
// - Perform a dynamic query that yields no results
// - Add data to the source of that query
// - Perform a the same query again
connection.Execute("CREATE TABLE #sut (value varchar(10) NOT NULL PRIMARY KEY)");
connection.Query("SELECT value FROM #sut").IsSequenceEqualTo(Enumerable.Empty<dynamic>());
connection.Execute("INSERT INTO #sut (value) VALUES ('test')").IsEqualTo(1);
var result = connection.Query("SELECT value FROM #sut");
var first = result.First();
((string)first.value).IsEqualTo("test");
}
public void TestIssue17648290()
{
var p = new DynamicParameters();
int code = 1, getMessageControlId = 2;
p.Add("@Code", code);
p.Add("@MessageControlId", getMessageControlId);
p.Add("@MessageControlID", getMessageControlId);
p.Add("@SuccessCode", dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("@ErrorDescription", dbType: DbType.String, direction: ParameterDirection.Output, size: 255);
connection.Execute(@"CREATE PROCEDURE #up_MessageProcessed_get
......
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Npgsql</id>
<version>2.0.11</version>
<title>Npgsql</title>
<authors>Jon Asher, Brar Piening, Chris Morgan, Dave Page, Federico Di Gregorio, Francisco Figueiredo jr., Hiroshi Saito, Josh Cooley, Jon Hanna</authors>
<owners>Jon Asher, Brar Piening, Chris Morgan, Dave Page, Federico Di Gregorio, Francisco Figueiredo jr., Hiroshi Saito, Josh Cooley, Jon Hanna</owners>
<licenseUrl>http://www.opensource.org/licenses/bsd-license.php</licenseUrl>
<projectUrl>http://pgfoundry.org/projects/npgsql/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Npgsql is a .Net data provider for Postgresql. It allows any program developed for .Net framework to access database server. It is implemented in 100% C# code. Works with Postgresql 7.x and 8.x.</description>
<summary>Npgsql is a .Net data provider for Postgresql.</summary>
<tags>Npgsql postgres data database</tags>
</metadata>
</package>
\ No newline at end of file
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>NuGet.CommandLine</id>
<version>2.0.40001</version>
<authors>Outercurve Foundation</authors>
<owners>Outercurve Foundation</owners>
<licenseUrl>http://nuget.codeplex.com/license</licenseUrl>
<projectUrl>http://nuget.codeplex.com/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>NuGet Command Line Tool</description>
</metadata>
</package>
\ No newline at end of file
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