Commit ae9d6da3 authored by mgravell's avatar mgravell

fix bug with Identity not applying type equality correctly; to avoid overhead,...

fix bug with Identity not applying type equality correctly; to avoid overhead, subclass Identity so we don't always need the arrays
parent 23ad634a
...@@ -406,7 +406,7 @@ private static DbCommand TrySetupAsyncCommand(this CommandDefinition command, ID ...@@ -406,7 +406,7 @@ private static DbCommand TrySetupAsyncCommand(this CommandDefinition command, ID
private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command) private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
bool wasClosed = cnn.State == ConnectionState.Closed; bool wasClosed = cnn.State == ConnectionState.Closed;
var cancel = command.CancellationToken; var cancel = command.CancellationToken;
...@@ -470,7 +470,7 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, ...@@ -470,7 +470,7 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn,
private static async Task<T> QueryRowAsync<T>(this IDbConnection cnn, Row row, Type effectiveType, CommandDefinition command) private static async Task<T> QueryRowAsync<T>(this IDbConnection cnn, Row row, Type effectiveType, CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
bool wasClosed = cnn.State == ConnectionState.Closed; bool wasClosed = cnn.State == ConnectionState.Closed;
var cancel = command.CancellationToken; var cancel = command.CancellationToken;
...@@ -594,7 +594,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD ...@@ -594,7 +594,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD
isFirst = false; isFirst = false;
cmd = command.TrySetupAsyncCommand(cnn, null); cmd = command.TrySetupAsyncCommand(cnn, null);
masterSql = cmd.CommandText; masterSql = cmd.CommandText;
var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null); var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType());
info = GetCacheInfo(identity, obj, command.AddToCache); info = GetCacheInfo(identity, obj, command.AddToCache);
} }
else if (pending.Count >= MAX_PENDING) else if (pending.Count >= MAX_PENDING)
...@@ -642,7 +642,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD ...@@ -642,7 +642,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD
{ {
masterSql = cmd.CommandText; masterSql = cmd.CommandText;
isFirst = false; isFirst = false;
var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null); var identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType());
info = GetCacheInfo(identity, obj, command.AddToCache); info = GetCacheInfo(identity, obj, command.AddToCache);
} }
else else
...@@ -667,7 +667,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD ...@@ -667,7 +667,7 @@ private static async Task<int> ExecuteMultiImplAsync(IDbConnection cnn, CommandD
private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, object param) private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, object param)
{ {
var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
bool wasClosed = cnn.State == ConnectionState.Closed; bool wasClosed = cnn.State == ConnectionState.Closed;
using (var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader)) using (var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader))
...@@ -935,7 +935,7 @@ private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefini ...@@ -935,7 +935,7 @@ private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefini
private static async Task<IEnumerable<TReturn>> MultiMapAsync<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn) private static async Task<IEnumerable<TReturn>> MultiMapAsync<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }); var identity = new Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
bool wasClosed = cnn.State == ConnectionState.Closed; bool wasClosed = cnn.State == ConnectionState.Closed;
try try
...@@ -985,7 +985,7 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC ...@@ -985,7 +985,7 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC
} }
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types); var identity = new IdentityWithTypes(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types);
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
bool wasClosed = cnn.State == ConnectionState.Closed; bool wasClosed = cnn.State == ConnectionState.Closed;
try try
...@@ -1037,7 +1037,7 @@ private static IEnumerable<T> ExecuteReaderSync<T>(IDataReader reader, Func<IDat ...@@ -1037,7 +1037,7 @@ private static IEnumerable<T> ExecuteReaderSync<T>(IDataReader reader, Func<IDat
public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, CommandDefinition command) public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType());
CacheInfo info = GetCacheInfo(identity, param, command.AddToCache); CacheInfo info = GetCacheInfo(identity, param, command.AddToCache);
DbCommand cmd = null; DbCommand cmd = null;
...@@ -1233,7 +1233,7 @@ private static async Task<T> ExecuteScalarImplAsync<T>(IDbConnection cnn, Comman ...@@ -1233,7 +1233,7 @@ private static async Task<T> ExecuteScalarImplAsync<T>(IDbConnection cnn, Comman
object param = command.Parameters; object param = command.Parameters;
if (param != null) if (param != null)
{ {
var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType());
paramReader = GetCacheInfo(identity, command.Parameters, command.AddToCache).ParamReader; paramReader = GetCacheInfo(identity, command.Parameters, command.AddToCache).ParamReader;
} }
......
...@@ -204,15 +204,7 @@ private T ReadRow<T>(Type type, Row row) ...@@ -204,15 +204,7 @@ private T ReadRow<T>(Type type, Row row)
private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Delegate func, string splitOn) private IEnumerable<TReturn> MultiReadInternal<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(Delegate func, string splitOn)
{ {
var identity = this.identity.ForGrid(typeof(TReturn), new Type[] { var identity = this.identity.ForGrid<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(typeof(TReturn), gridIndex);
typeof(TFirst),
typeof(TSecond),
typeof(TThird),
typeof(TFourth),
typeof(TFifth),
typeof(TSixth),
typeof(TSeventh)
}, gridIndex);
IsConsumed = true; IsConsumed = true;
......
using System; using System;
using System.Data; using System.Data;
using System.Runtime.CompilerServices;
namespace Dapper namespace Dapper
{ {
public static partial class SqlMapper public static partial class SqlMapper
{ {
internal sealed class Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh> : Identity
{
private static readonly int s_typeHash;
private static readonly int s_typeCount = CountNonTrivial(out s_typeHash);
internal Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, int gridIndex = 0)
: base(sql, commandType, connectionString, type, parametersType, s_typeHash, gridIndex)
{}
internal Identity(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, int gridIndex = 0)
: base(sql, commandType, connection.ConnectionString, type, parametersType, s_typeHash, gridIndex)
{ }
static int CountNonTrivial(out int hashCode)
{
int hashCodeLocal = 0;
int count = 0;
bool Map<T>()
{
if(typeof(T) != typeof(DontMap))
{
count++;
hashCodeLocal = (hashCodeLocal * 23) + (typeof(T).GetHashCode());
return true;
}
return false;
}
_ = Map<TFirst>() && Map<TSecond>() && Map<TThird>()
&& Map<TFourth>() && Map<TFifth>() && Map<TSixth>()
&& Map<TSeventh>();
hashCode = hashCodeLocal;
return count;
}
internal override int TypeCount => s_typeCount;
internal override Type GetType(int index)
{
switch (index)
{
case 0: return typeof(TFirst);
case 1: return typeof(TSecond);
case 2: return typeof(TThird);
case 3: return typeof(TFourth);
case 4: return typeof(TFifth);
case 5: return typeof(TSixth);
case 6: return typeof(TSeventh);
default: return base.GetType(index);
}
}
}
internal sealed class IdentityWithTypes : Identity
{
private readonly Type[] _types;
internal IdentityWithTypes(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, Type[] otherTypes, int gridIndex = 0)
: base(sql, commandType, connectionString, type, parametersType, HashTypes(otherTypes), gridIndex)
{
_types = otherTypes ?? Type.EmptyTypes;
}
internal IdentityWithTypes(string sql, CommandType? commandType, IDbConnection connection, Type type, Type parametersType, Type[] otherTypes, int gridIndex = 0)
: base(sql, commandType, connection.ConnectionString, type, parametersType, HashTypes(otherTypes), gridIndex)
{
_types = otherTypes ?? Type.EmptyTypes;
}
internal override int TypeCount => _types.Length;
internal override Type GetType(int index) => _types[index];
static int HashTypes(Type[] types)
{
var hashCode = 0;
if (types != null)
{
foreach (var t in types)
{
hashCode = (hashCode * 23) + (t?.GetHashCode() ?? 0);
}
}
return hashCode;
}
}
/// <summary> /// <summary>
/// Identity of a cached query in Dapper, used for extensibility. /// Identity of a cached query in Dapper, used for extensibility.
/// </summary> /// </summary>
public class Identity : IEquatable<Identity> public class Identity : IEquatable<Identity>
{ {
internal virtual int TypeCount => 0;
internal virtual Type GetType(int index) => throw new IndexOutOfRangeException(nameof(index));
internal Identity ForGrid<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(Type primaryType, int gridIndex) =>
new Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(sql, commandType, connectionString, primaryType, parametersType, gridIndex);
internal Identity ForGrid(Type primaryType, int gridIndex) => internal Identity ForGrid(Type primaryType, int gridIndex) =>
new Identity(sql, commandType, connectionString, primaryType, parametersType, null, gridIndex); new Identity(sql, commandType, connectionString, primaryType, parametersType, 0, gridIndex);
internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex) => internal Identity ForGrid(Type primaryType, Type[] otherTypes, int gridIndex) =>
new Identity(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex); (otherTypes == null || otherTypes.Length == 0)
? new Identity(sql, commandType, connectionString, primaryType, parametersType, 0, gridIndex)
: new IdentityWithTypes(sql, commandType, connectionString, primaryType, parametersType, otherTypes, gridIndex);
/// <summary> /// <summary>
/// Create an identity for use with DynamicParameters, internal use only. /// Create an identity for use with DynamicParameters, internal use only.
...@@ -22,12 +113,12 @@ public class Identity : IEquatable<Identity> ...@@ -22,12 +113,12 @@ public class Identity : IEquatable<Identity>
/// <param name="type">The parameters type to create an <see cref="Identity"/> for.</param> /// <param name="type">The parameters type to create an <see cref="Identity"/> for.</param>
/// <returns></returns> /// <returns></returns>
public Identity ForDynamicParameters(Type type) => public Identity ForDynamicParameters(Type type) =>
new Identity(sql, commandType, connectionString, this.type, type, null, -1); new Identity(sql, commandType, connectionString, this.type, type, 0, -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)
: this(sql, commandType, connection.ConnectionString, type, parametersType, otherTypes, 0) { /* base call */ } : this(sql, commandType, connection.ConnectionString, type, parametersType, 0, 0) { /* base call */ }
private Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, Type[] otherTypes, int gridIndex) private protected Identity(string sql, CommandType? commandType, string connectionString, Type type, Type parametersType, int otherTypesHash, int gridIndex)
{ {
this.sql = sql; this.sql = sql;
this.commandType = commandType; this.commandType = commandType;
...@@ -42,13 +133,7 @@ private Identity(string sql, CommandType? commandType, string connectionString, ...@@ -42,13 +133,7 @@ private Identity(string sql, CommandType? commandType, string connectionString,
hashCode = (hashCode * 23) + gridIndex.GetHashCode(); hashCode = (hashCode * 23) + gridIndex.GetHashCode();
hashCode = (hashCode * 23) + (sql?.GetHashCode() ?? 0); hashCode = (hashCode * 23) + (sql?.GetHashCode() ?? 0);
hashCode = (hashCode * 23) + (type?.GetHashCode() ?? 0); hashCode = (hashCode * 23) + (type?.GetHashCode() ?? 0);
if (otherTypes != null) hashCode = (hashCode * 23) + otherTypesHash;
{
foreach (var t in otherTypes)
{
hashCode = (hashCode * 23) + (t?.GetHashCode() ?? 0);
}
}
hashCode = (hashCode * 23) + (connectionString == null ? 0 : connectionStringComparer.GetHashCode(connectionString)); hashCode = (hashCode * 23) + (connectionString == null ? 0 : connectionStringComparer.GetHashCode(connectionString));
hashCode = (hashCode * 23) + (parametersType?.GetHashCode() ?? 0); hashCode = (hashCode * 23) + (parametersType?.GetHashCode() ?? 0);
} }
...@@ -101,6 +186,11 @@ private Identity(string sql, CommandType? commandType, string connectionString, ...@@ -101,6 +186,11 @@ private Identity(string sql, CommandType? commandType, string connectionString,
/// <returns></returns> /// <returns></returns>
public override int GetHashCode() => hashCode; public override int GetHashCode() => hashCode;
/// <summary>
/// See object.ToString()
/// </summary>
public override string ToString() => sql;
/// <summary> /// <summary>
/// Compare 2 Identity objects /// Compare 2 Identity objects
/// </summary> /// </summary>
...@@ -108,13 +198,30 @@ private Identity(string sql, CommandType? commandType, string connectionString, ...@@ -108,13 +198,30 @@ private Identity(string sql, CommandType? commandType, string connectionString,
/// <returns>Whether the two are equal</returns> /// <returns>Whether the two are equal</returns>
public bool Equals(Identity other) public bool Equals(Identity other)
{ {
return other != null if (ReferenceEquals(this, other)) return true;
&& gridIndex == other.gridIndex if (ReferenceEquals(other, null)) return false;
int typeCount;
return gridIndex == other.gridIndex
&& type == other.type && type == other.type
&& sql == other.sql && sql == other.sql
&& commandType == other.commandType && commandType == other.commandType
&& connectionStringComparer.Equals(connectionString, other.connectionString) && connectionStringComparer.Equals(connectionString, other.connectionString)
&& parametersType == other.parametersType; && parametersType == other.parametersType
&& (typeCount = TypeCount) == other.TypeCount
&& (typeCount == 0 || TypesEqual(this, other, typeCount));
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static bool TypesEqual(Identity x, Identity y, int count)
{
if (y.TypeCount != count) return false;
for(int i = 0; i < count; i++)
{
if (x.GetType(i) != y.GetType(i))
return false;
}
return true;
} }
} }
} }
......
...@@ -538,7 +538,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com ...@@ -538,7 +538,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
{ {
masterSql = cmd.CommandText; masterSql = cmd.CommandText;
isFirst = false; isFirst = false;
identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType(), null); identity = new Identity(command.CommandText, cmd.CommandType, cnn, null, obj.GetType());
info = GetCacheInfo(identity, obj, command.AddToCache); info = GetCacheInfo(identity, obj, command.AddToCache);
} }
else else
...@@ -562,7 +562,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com ...@@ -562,7 +562,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com
// nice and simple // nice and simple
if (param != null) if (param != null)
{ {
identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null); identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType());
info = GetCacheInfo(identity, param, command.AddToCache); info = GetCacheInfo(identity, param, command.AddToCache);
} }
return ExecuteCommand(cnn, ref command, param == null ? null : info.ParamReader); return ExecuteCommand(cnn, ref command, param == null ? null : info.ParamReader);
...@@ -1007,7 +1007,7 @@ public static GridReader QueryMultiple(this IDbConnection cnn, string sql, objec ...@@ -1007,7 +1007,7 @@ public static GridReader QueryMultiple(this IDbConnection cnn, string sql, objec
private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandDefinition command) private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, typeof(GridReader), param?.GetType());
CacheInfo info = GetCacheInfo(identity, param, command.AddToCache); CacheInfo info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null; IDbCommand cmd = null;
...@@ -1064,7 +1064,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w ...@@ -1064,7 +1064,7 @@ private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool w
private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType) private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null; IDbCommand cmd = null;
...@@ -1162,7 +1162,7 @@ private static void ThrowZeroRows(Row row) ...@@ -1162,7 +1162,7 @@ private static void ThrowZeroRows(Row row)
private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefinition command, Type effectiveType) private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefinition command, Type effectiveType)
{ {
object param = command.Parameters; object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param?.GetType());
var info = GetCacheInfo(identity, param, command.AddToCache); var info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null; IDbCommand cmd = null;
...@@ -1405,7 +1405,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1405,7 +1405,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
private static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn, IDataReader reader, Identity identity, bool finalize) private static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, CommandDefinition command, Delegate map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{ {
object param = command.Parameters; object param = command.Parameters;
identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType(), new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }); identity = identity ?? new Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(command.CommandText, command.CommandType, cnn, typeof(TFirst), param?.GetType());
CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache); CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand ownedCommand = null; IDbCommand ownedCommand = null;
...@@ -1427,7 +1427,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1427,7 +1427,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
int hash = GetColumnHash(reader); int hash = GetColumnHash(reader);
if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash) if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)
{ {
var deserializers = GenerateDeserializers(new[] { typeof(TFirst), typeof(TSecond), typeof(TThird), typeof(TFourth), typeof(TFifth), typeof(TSixth), typeof(TSeventh) }, splitOn, reader); var deserializers = GenerateDeserializers(identity, splitOn, reader);
deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]); deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);
otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray(); otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();
if (command.AddToCache) SetQueryCache(identity, cinfo); if (command.AddToCache) SetQueryCache(identity, cinfo);
...@@ -1475,7 +1475,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1475,7 +1475,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
} }
object param = command.Parameters; object param = command.Parameters;
identity = identity ?? new Identity(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types); identity = identity ?? new IdentityWithTypes(command.CommandText, command.CommandType, cnn, types[0], param?.GetType(), types);
CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache); CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand ownedCommand = null; IDbCommand ownedCommand = null;
...@@ -1497,7 +1497,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1497,7 +1497,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
int hash = GetColumnHash(reader); int hash = GetColumnHash(reader);
if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash) if ((deserializer = cinfo.Deserializer).Func == null || (otherDeserializers = cinfo.OtherDeserializers) == null || hash != deserializer.Hash)
{ {
var deserializers = GenerateDeserializers(types, splitOn, reader); var deserializers = GenerateDeserializers(identity, splitOn, reader);
deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]); deserializer = cinfo.Deserializer = new DeserializerState(hash, deserializers[0]);
otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray(); otherDeserializers = cinfo.OtherDeserializers = deserializers.Skip(1).ToArray();
SetQueryCache(identity, cinfo); SetQueryCache(identity, cinfo);
...@@ -1569,12 +1569,14 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1569,12 +1569,14 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
}; };
} }
private static Func<IDataReader, object>[] GenerateDeserializers(Type[] types, string splitOn, IDataReader reader) private static Func<IDataReader, object>[] GenerateDeserializers(Identity identity, string splitOn, IDataReader reader)
{ {
var deserializers = new List<Func<IDataReader, object>>(); var deserializers = new List<Func<IDataReader, object>>();
var splits = splitOn.Split(',').Select(s => s.Trim()).ToArray(); var splits = splitOn.Split(',').Select(s => s.Trim()).ToArray();
bool isMultiSplit = splits.Length > 1; bool isMultiSplit = splits.Length > 1;
if (types[0] == typeof(object))
int typeCount = identity.TypeCount;
if (identity.GetType(0) == typeof(object))
{ {
// we go left to right for dynamic multi-mapping so that the madness of TestMultiMappingVariations // we go left to right for dynamic multi-mapping so that the madness of TestMultiMappingVariations
// is supported // is supported
...@@ -1582,8 +1584,10 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1582,8 +1584,10 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
int currentPos = 0; int currentPos = 0;
int splitIdx = 0; int splitIdx = 0;
string currentSplit = splits[splitIdx]; string currentSplit = splits[splitIdx];
foreach (var type in types)
for (int i = 0; i < typeCount; i++)
{ {
Type type = identity.GetType(i);
if (type == typeof(DontMap)) if (type == typeof(DontMap))
{ {
break; break;
...@@ -1606,9 +1610,9 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn ...@@ -1606,9 +1610,9 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn
int currentPos = reader.FieldCount; int currentPos = reader.FieldCount;
int splitIdx = splits.Length - 1; int splitIdx = splits.Length - 1;
var currentSplit = splits[splitIdx]; var currentSplit = splits[splitIdx];
for (var typeIdx = types.Length - 1; typeIdx >= 0; --typeIdx) for (var typeIdx = typeCount - 1; typeIdx >= 0; --typeIdx)
{ {
var type = types[typeIdx]; var type = identity.GetType(typeIdx);
if (type == typeof(DontMap)) if (type == typeof(DontMap))
{ {
continue; continue;
...@@ -2807,7 +2811,7 @@ private static T ExecuteScalarImpl<T>(IDbConnection cnn, ref CommandDefinition c ...@@ -2807,7 +2811,7 @@ private static T ExecuteScalarImpl<T>(IDbConnection cnn, ref CommandDefinition c
object param = command.Parameters; object param = command.Parameters;
if (param != null) if (param != null)
{ {
var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType());
paramReader = GetCacheInfo(identity, command.Parameters, command.AddToCache).ParamReader; paramReader = GetCacheInfo(identity, command.Parameters, command.AddToCache).ParamReader;
} }
...@@ -2864,7 +2868,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin ...@@ -2864,7 +2868,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin
// nice and simple // nice and simple
if (param != null) if (param != null)
{ {
var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType(), null); var identity = new Identity(command.CommandText, command.CommandType, cnn, null, param.GetType());
info = GetCacheInfo(identity, param, command.AddToCache); info = GetCacheInfo(identity, param, command.AddToCache);
} }
var paramReader = info?.ParamReader; var paramReader = info?.ParamReader;
......
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