Commit 42e8f946 authored by Marc Gravell's avatar Marc Gravell

Merge pull request #168 from StackExchange/fix_detached_head

Fix detached head
parents b87d9583 863c4c27
...@@ -4297,14 +4297,20 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity) ...@@ -4297,14 +4297,20 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
} }
// Now that the parameters are added to the command, let's place our output callbacks // Now that the parameters are added to the command, let's place our output callbacks
foreach (var generator in this.outputCallbacks) var tmp = outputCallbacks;
if (tmp != null)
{ {
generator(); foreach (var generator in tmp)
{
generator();
}
} }
} }
foreach (var param in parameters.Values.Where(p => !p.CameFromTemplate)) foreach (var param in parameters.Values)
{ {
if (param.CameFromTemplate) continue;
var dbType = param.DbType; var dbType = param.DbType;
var val = param.Value; var val = param.Value;
string name = Clean(param.Name); string name = Clean(param.Name);
...@@ -4428,13 +4434,13 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -4428,13 +4434,13 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
var failMessage = "Expression must be a property/field chain off of a(n) {0} instance"; var failMessage = "Expression must be a property/field chain off of a(n) {0} instance";
failMessage = string.Format(failMessage, typeof(T).Name); failMessage = string.Format(failMessage, typeof(T).Name);
Action @throw = () => { throw new InvalidOperationException(failMessage); }; Action @throw = () => { throw new InvalidOperationException(failMessage); };
// Is it even a MemberExpression? // Is it even a MemberExpression?
var lastMemberAccess = expression.Body as MemberExpression; var lastMemberAccess = expression.Body as MemberExpression;
if (lastMemberAccess == null || if (lastMemberAccess == null ||
(lastMemberAccess.Member.MemberType != MemberTypes.Property && (lastMemberAccess.Member.MemberType != MemberTypes.Property &&
lastMemberAccess.Member.MemberType != MemberTypes.Field)) lastMemberAccess.Member.MemberType != MemberTypes.Field))
{ {
if (expression.Body.NodeType == ExpressionType.Convert && if (expression.Body.NodeType == ExpressionType.Convert &&
expression.Body.Type == typeof(object) && expression.Body.Type == typeof(object) &&
...@@ -4468,27 +4474,24 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -4468,27 +4474,24 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
{ {
break; break;
} }
else if (diving == null || else if (diving == null ||
(diving.Member.MemberType != MemberTypes.Property && (diving.Member.MemberType != MemberTypes.Property &&
diving.Member.MemberType != MemberTypes.Field)) diving.Member.MemberType != MemberTypes.Field))
{ {
@throw(); @throw();
} }
} }
while (diving != null); while (diving != null);
var dynamicParamName = string.Join(string.Empty, names.ToArray()); var dynamicParamName = string.Join(string.Empty, names.ToArray());
// Before we get all emitty... // Before we get all emitty...
var lookup = typeof(T).Name + "_" + string.Join("|", names.ToArray()); var lookup = string.Join("|", names.ToArray());
Action<object, DynamicParameters> setter = null;
lock (cachedOutputSettersLock) var cache = CachedOutputSetters<T>.Cache;
{ var setter = (Action<object, DynamicParameters>)cache[lookup];
if (cachedOutputSetters.TryGetValue(lookup, out setter))
{ if (setter != null) goto MAKECALLBACK;
goto MAKECALLBACK;
}
}
// Come on let's build a method, let's build it, let's build it now! // Come on let's build a method, let's build it, let's build it now!
var dm = new DynamicMethod(string.Format("ExpressionParam{0}", Guid.NewGuid()), null, new[] { typeof(object), this.GetType() }, true); var dm = new DynamicMethod(string.Format("ExpressionParam{0}", Guid.NewGuid()), null, new[] { typeof(object), this.GetType() }, true);
...@@ -4535,17 +4538,14 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -4535,17 +4538,14 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
il.Emit(OpCodes.Ret); // GO il.Emit(OpCodes.Ret); // GO
setter = (Action<object, DynamicParameters>)dm.CreateDelegate(typeof(Action<object, DynamicParameters>)); setter = (Action<object, DynamicParameters>)dm.CreateDelegate(typeof(Action<object, DynamicParameters>));
lock (cachedOutputSettersLock) lock (cache)
{ {
if (!cachedOutputSetters.ContainsKey(lookup)) cache[lookup] = setter;
{
cachedOutputSetters.Add(lookup, setter);
}
} }
// Queue the preparation to be fired off when adding parameters to the DbCommand // Queue the preparation to be fired off when adding parameters to the DbCommand
MAKECALLBACK: MAKECALLBACK:
this.outputCallbacks.Add(() => (outputCallbacks ?? (outputCallbacks = new List<Action>())).Add(() =>
{ {
// Finally, prep the parameter and attach the callback to it // Finally, prep the parameter and attach the callback to it
ParamInfo parameter; ParamInfo parameter;
...@@ -4579,11 +4579,14 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express ...@@ -4579,11 +4579,14 @@ public DynamicParameters Output<T>(T target, Expression<Func<T, object>> express
return this; return this;
} }
private readonly List<Action> outputCallbacks = new List<Action>(); private List<Action> outputCallbacks;
private readonly Dictionary<string, Action<object, DynamicParameters>> cachedOutputSetters = new Dictionary<string,Action<object,DynamicParameters>>(); private readonly Dictionary<string, Action<object, DynamicParameters>> cachedOutputSetters = new Dictionary<string,Action<object,DynamicParameters>>();
private readonly object cachedOutputSettersLock = new object(); internal static class CachedOutputSetters<T>
{
public static readonly Hashtable Cache = new Hashtable();
}
internal void FireOutputCallbacks() internal void FireOutputCallbacks()
{ {
......
...@@ -1176,7 +1176,6 @@ public void TestSupportForDynamicParameters() ...@@ -1176,7 +1176,6 @@ public void TestSupportForDynamicParameters()
p.Get<int>("age").IsEqualTo(11); p.Get<int>("age").IsEqualTo(11);
} }
[ActiveTest]
public void TestSupportForDynamicParametersOutputExpressions() public void TestSupportForDynamicParametersOutputExpressions()
{ {
var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } };
......
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