Commit 27b41cc5 authored by Sam Saffron's avatar Sam Saffron

Add support for DynamicParams to append objects

EG:

  DynamicParameters p = new DynamicParameters();
  p.AddDynamicParams(new { A = 1, B = 2 });
  p.AddDynamicParams(new { C = 3, D = 4 });

Expose some more of dapper's internals
parent c873a24d
...@@ -23,7 +23,7 @@ public static partial class SqlMapper ...@@ -23,7 +23,7 @@ public static partial class SqlMapper
{ {
public interface IDynamicParameters public interface IDynamicParameters
{ {
void AddParameters(IDbCommand command); void AddParameters(IDbCommand command, Identity identity);
} }
static Link<Type, Action<IDbCommand, bool>> bindByNameCache; static Link<Type, Action<IDbCommand, bool>> bindByNameCache;
static Action<IDbCommand, bool> GetBindByName(Type commandType) static Action<IDbCommand, bool> GetBindByName(Type commandType)
...@@ -279,7 +279,7 @@ private static DbType LookupDbType(Type type, string name) ...@@ -279,7 +279,7 @@ private static DbType LookupDbType(Type type, string name)
throw new NotSupportedException(string.Format("The member {0} of type {1} cannot be used as a parameter value", name, type)); throw new NotSupportedException(string.Format("The member {0} of type {1} cannot be used as a parameter value", name, type));
} }
internal class Identity : IEquatable<Identity> public class Identity : IEquatable<Identity>
{ {
internal Identity ForGrid(Type primaryType, int gridIndex) internal Identity ForGrid(Type primaryType, int gridIndex)
{ {
...@@ -291,6 +291,11 @@ internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex) ...@@ -291,6 +291,11 @@ internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex)
return new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex); return new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);
} }
public Identity ForDynamicParameters(Type type)
{
return new Identity(sql, commandType, connectionString, this.type ,type, null, -1);
}
internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, Type[] otherTypes) internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, Type[] otherTypes)
: this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0) : this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0)
{ } { }
...@@ -324,12 +329,12 @@ public override bool Equals(object obj) ...@@ -324,12 +329,12 @@ public override bool Equals(object obj)
{ {
return Equals(obj as Identity); return Equals(obj as Identity);
} }
internal readonly string sql; public readonly string sql;
internal readonly CommandType? commandType; public readonly CommandType? commandType;
internal readonly int hashCode, gridIndex; public readonly int hashCode, gridIndex;
private readonly Type type; private readonly Type type;
internal readonly string connectionString; public readonly string connectionString;
internal readonly Type parametersType; public readonly Type parametersType;
public override int GetHashCode() public override int GetHashCode()
{ {
return hashCode; return hashCode;
...@@ -777,7 +782,7 @@ private static CacheInfo GetCacheInfo(Identity identity) ...@@ -777,7 +782,7 @@ private static CacheInfo GetCacheInfo(Identity identity)
{ {
if (typeof(IDynamicParameters).IsAssignableFrom(identity.parametersType)) if (typeof(IDynamicParameters).IsAssignableFrom(identity.parametersType))
{ {
info.ParamReader = (cmd, obj) => { (obj as IDynamicParameters).AddParameters(cmd); }; info.ParamReader = (cmd, obj) => { (obj as IDynamicParameters).AddParameters(cmd,identity); };
} }
else else
{ {
...@@ -1040,7 +1045,7 @@ private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyIn ...@@ -1040,7 +1045,7 @@ private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyIn
return parameters.Where(p => Regex.IsMatch(sql, "[@:]" + p.Name + "([^a-zA-Z0-9_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline)); return parameters.Where(p => Regex.IsMatch(sql, "[@:]" + p.Name + "([^a-zA-Z0-9_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline));
} }
private static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity) public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity)
{ {
Type type = identity.parametersType; Type type = identity.parametersType;
bool filterParams = identity.commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text; bool filterParams = identity.commandType.GetValueOrDefault(CommandType.Text) == CommandType.Text;
...@@ -1660,7 +1665,10 @@ public void Dispose() ...@@ -1660,7 +1665,10 @@ public void Dispose()
} }
public class DynamicParameters : SqlMapper.IDynamicParameters public class DynamicParameters : SqlMapper.IDynamicParameters
{ {
static Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();
Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>(); Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>();
List<object> templates;
class ParamInfo class ParamInfo
{ {
...@@ -1675,21 +1683,31 @@ class ParamInfo ...@@ -1675,21 +1683,31 @@ class ParamInfo
public DynamicParameters() { } public DynamicParameters() { }
public DynamicParameters(object template) public DynamicParameters(object template)
{ {
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
if (template != null) if (template != null)
{ {
foreach (PropertyInfo prop in template.GetType().GetProperties(bindingFlags)) AddDynamicParams(template);
{ }
if (!prop.CanRead) continue; }
var idx = prop.GetIndexParameters();
if (idx != null && idx.Length != 0) continue; /// <summary>
Add(prop.Name, prop.GetValue(template, null), null, ParameterDirection.Input, null); /// Append a whole object full of params to the dynamic
} /// EG: AddParams(new {A = 1, B = 2}) // will add property A and B to the dynamic
foreach (FieldInfo field in template.GetType().GetFields(bindingFlags)) /// </summary>
{ /// <param name="param"></param>
Add(field.Name, field.GetValue(template), null, ParameterDirection.Input, null); public void AddDynamicParams(
} #if CSHARP30
object param
#else
dynamic param
#endif
)
{
object obj = param as object;
if (obj != null)
{
templates = templates ?? new List<object>();
templates.Add(obj);
} }
} }
...@@ -1720,8 +1738,28 @@ static string Clean(string name) ...@@ -1720,8 +1738,28 @@ static string Clean(string name)
return name; return name;
} }
void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command) void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Identity identity)
{ {
if (templates != null)
{
foreach (var template in templates)
{
var newIdent = identity.ForDynamicParameters(template.GetType());
Action<IDbCommand, object> appender;
lock (paramReaderCache)
{
if (!paramReaderCache.TryGetValue(newIdent, out appender))
{
appender = SqlMapper.CreateParamInfoGenerator(newIdent);
paramReaderCache[newIdent] = appender;
}
}
appender(command, template);
}
}
foreach (var param in parameters.Values) foreach (var param in parameters.Values)
{ {
var p = command.CreateParameter(); var p = command.CreateParameter();
......
...@@ -11,10 +11,8 @@ ...@@ -11,10 +11,8 @@
namespace SqlMapper namespace SqlMapper
{ {
class Tests class Tests
{ {
SqlConnection connection = Program.GetOpenConnection(); SqlConnection connection = Program.GetOpenConnection();
public void SelectListInt() public void SelectListInt()
...@@ -757,7 +755,7 @@ public IntDynamicParam(IEnumerable<int> numbers) ...@@ -757,7 +755,7 @@ public IntDynamicParam(IEnumerable<int> numbers)
this.numbers = numbers; this.numbers = numbers;
} }
public void AddParameters(IDbCommand command) public void AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity)
{ {
var sqlCommand = (SqlCommand)command; var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure; sqlCommand.CommandType = CommandType.StoredProcedure;
...@@ -1051,5 +1049,32 @@ public void TestWithNonPublicConstructor() ...@@ -1051,5 +1049,32 @@ public void TestWithNonPublicConstructor()
var output = connection.Query<WithPrivateConstructor>("select 1 as Foo").First(); var output = connection.Query<WithPrivateConstructor>("select 1 as Foo").First();
output.Foo.IsEqualTo(1); output.Foo.IsEqualTo(1);
} }
public void TestAppendingAnonClasses()
{
DynamicParameters p = new DynamicParameters();
p.AddDynamicParams(new { A = 1, B = 2 });
p.AddDynamicParams(new { C = 3, D = 4 });
var result = connection.Query("select @A a,@B b,@C c,@D d", p).Single();
((int)result.a).IsEqualTo(1);
((int)result.b).IsEqualTo(2);
((int)result.c).IsEqualTo(3);
((int)result.d).IsEqualTo(4);
}
public void TestAppendingAList()
{
DynamicParameters p = new DynamicParameters();
var list = new int[] {1,2,3};
p.AddDynamicParams(new { list });
var result = connection.Query<int>("select * from (select 1 A union all select 2 union all select 3) X where A in @list", p).ToList();
result[0].IsEqualTo(1);
result[1].IsEqualTo(2);
result[2].IsEqualTo(3);
}
} }
} }
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