Commit 9e67f97f authored by Nick Craver's avatar Nick Craver

Merge branch 'master' of https://github.com/StackExchange/Dapper

parents 7b34be3a 967a4a0a
...@@ -30,6 +30,10 @@ namespace Dapper ...@@ -30,6 +30,10 @@ namespace Dapper
/// </summary> /// </summary>
public static partial class SqlMapper public static partial class SqlMapper
{ {
private class PropertyInfoByNameComparer : IComparer<PropertyInfo>
{
public int Compare(PropertyInfo x, PropertyInfo y) => string.CompareOrdinal(x.Name, y.Name);
}
private static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1) private static int GetColumnHash(IDataReader reader, int startBound = 0, int length = -1)
{ {
unchecked unchecked
...@@ -2217,7 +2221,13 @@ public static object SanitizeParameterValue(object value) ...@@ -2217,7 +2221,13 @@ public static object SanitizeParameterValue(object value)
private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyInfo> parameters, string sql) private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyInfo> parameters, string sql)
{ {
return parameters.Where(p => Regex.IsMatch(sql, "[?@:]" + p.Name + @"([^\p{L}\p{N}_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant)); var list = new List<PropertyInfo>(16);
foreach (var p in parameters)
{
if (Regex.IsMatch(sql, @"[?@:]" + p.Name + @"([^\p{L}\p{N}_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant))
list.Add(p);
}
return list;
} }
// look for ? / @ / : *by itself* // look for ? / @ / : *by itself*
...@@ -2356,7 +2366,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2356,7 +2366,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused) => public static Action<IDbCommand, object> CreateParamInfoGenerator(Identity identity, bool checkForDuplicates, bool removeUnused) =>
CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity.sql)); CreateParamInfoGenerator(identity, checkForDuplicates, removeUnused, GetLiteralTokens(identity.sql));
private static bool IsValueTuple(Type type) => type?.IsValueType() == true && type.FullName.StartsWith("System.ValueTuple`"); private static bool IsValueTuple(Type type) => type?.IsValueType() == true && type.FullName.StartsWith("System.ValueTuple`", StringComparison.Ordinal);
private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
{ {
...@@ -2415,19 +2425,27 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2415,19 +2425,27 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
il.Emit(OpCodes.Ldarg_0); // stack is now [command] il.Emit(OpCodes.Ldarg_0); // stack is now [command]
il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetProperty(nameof(IDbCommand.Parameters)).GetGetMethod(), null); // stack is now [parameters] il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetProperty(nameof(IDbCommand.Parameters)).GetGetMethod(), null); // stack is now [parameters]
var propsArr = type.GetProperties().Where(p => p.GetIndexParameters().Length == 0).ToArray(); var allTypeProps = type.GetProperties();
var propsList = new List<PropertyInfo>(allTypeProps.Length);
for(int i = 0; i < allTypeProps.Length; ++i)
{
var p = allTypeProps[i];
if (p.GetIndexParameters().Length == 0)
propsList.Add(p);
}
var ctors = type.GetConstructors(); var ctors = type.GetConstructors();
ParameterInfo[] ctorParams; ParameterInfo[] ctorParams;
IEnumerable<PropertyInfo> props = null; IEnumerable<PropertyInfo> props = null;
// try to detect tuple patterns, e.g. anon-types, and use that to choose the order // try to detect tuple patterns, e.g. anon-types, and use that to choose the order
// otherwise: alphabetical // otherwise: alphabetical
if (ctors.Length == 1 && propsArr.Length == (ctorParams = ctors[0].GetParameters()).Length) if (ctors.Length == 1 && propsList.Count == (ctorParams = ctors[0].GetParameters()).Length)
{ {
// check if reflection was kind enough to put everything in the right order for us // check if reflection was kind enough to put everything in the right order for us
bool ok = true; bool ok = true;
for (int i = 0; i < propsArr.Length; i++) for (int i = 0; i < propsList.Count; i++)
{ {
if (!string.Equals(propsArr[i].Name, ctorParams[i].Name, StringComparison.OrdinalIgnoreCase)) if (!string.Equals(propsList[i].Name, ctorParams[i].Name, StringComparison.OrdinalIgnoreCase))
{ {
ok = false; ok = false;
break; break;
...@@ -2436,7 +2454,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2436,7 +2454,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
if(ok) if(ok)
{ {
// pre-sorted; the reflection gods have smiled upon us // pre-sorted; the reflection gods have smiled upon us
props = propsArr; props = propsList;
} }
else { // might still all be accounted for; check the hard way else { // might still all be accounted for; check the hard way
var positionByName = new Dictionary<string,int>(StringComparer.OrdinalIgnoreCase); var positionByName = new Dictionary<string,int>(StringComparer.OrdinalIgnoreCase);
...@@ -2444,13 +2462,13 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2444,13 +2462,13 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
{ {
positionByName[param.Name] = param.Position; positionByName[param.Name] = param.Position;
} }
if (positionByName.Count == propsArr.Length) if (positionByName.Count == propsList.Count)
{ {
int[] positions = new int[propsArr.Length]; int[] positions = new int[propsList.Count];
ok = true; ok = true;
for (int i = 0; i < propsArr.Length; i++) for (int i = 0; i < propsList.Count; i++)
{ {
if (!positionByName.TryGetValue(propsArr[i].Name, out int pos)) if (!positionByName.TryGetValue(propsList[i].Name, out int pos))
{ {
ok = false; ok = false;
break; break;
...@@ -2459,13 +2477,17 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2459,13 +2477,17 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
} }
if (ok) if (ok)
{ {
Array.Sort(positions, propsArr); props = propsList.ToArray();
props = propsArr; Array.Sort(positions, (PropertyInfo[]) props);
} }
} }
} }
} }
props = props ?? propsArr.OrderBy(x => x.Name); if(props == null)
{
propsList.Sort(new PropertyInfoByNameComparer());
props = propsList;
}
if (filterParams) if (filterParams)
{ {
props = FilterParameters(props, identity.sql); props = FilterParameters(props, identity.sql);
...@@ -2677,7 +2699,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2677,7 +2699,7 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
// stack is currently [parameters] // stack is currently [parameters]
il.Emit(OpCodes.Pop); // stack is now empty il.Emit(OpCodes.Pop); // stack is now empty
if(literals.Count != 0 && propsArr != null) if(literals.Count != 0 && propsList != null)
{ {
il.Emit(OpCodes.Ldarg_0); // command il.Emit(OpCodes.Ldarg_0); // command
il.Emit(OpCodes.Ldarg_0); // command, command il.Emit(OpCodes.Ldarg_0); // command, command
...@@ -2690,12 +2712,12 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names) ...@@ -2690,12 +2712,12 @@ private static List<IMemberMap> GetValueTupleMembers(Type type, string[] names)
// find the best member, preferring case-sensitive // find the best member, preferring case-sensitive
PropertyInfo exact = null, fallback = null; PropertyInfo exact = null, fallback = null;
string huntName = literal.Member; string huntName = literal.Member;
for(int i = 0; i < propsArr.Length;i++) for(int i = 0; i < propsList.Count; i++)
{ {
string thisName = propsArr[i].Name; string thisName = propsList[i].Name;
if(string.Equals(thisName, huntName, StringComparison.OrdinalIgnoreCase)) if(string.Equals(thisName, huntName, StringComparison.OrdinalIgnoreCase))
{ {
fallback = propsArr[i]; fallback = propsList[i];
if(string.Equals(thisName, huntName, StringComparison.Ordinal)) if(string.Equals(thisName, huntName, StringComparison.Ordinal))
{ {
exact = fallback; exact = fallback;
......
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