Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dapper/SqlMapper.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TFirst, TSecond, T
using var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader);
using var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false);
if (!command.Buffered) wasClosed = false; // handing back open reader; rely on command-behavior
var results = MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, CommandDefinition.ForCallback(command.Parameters, command.Flags), map, splitOn, reader, identity, true);
var results = MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, CommandDefinition.ForCallback(command.Parameters, command.Flags), map, splitOn, reader, identity, true, info);
return command.Buffered ? results.ToList() : results;
}
finally
Expand Down Expand Up @@ -988,7 +988,7 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC
if (wasClosed) await cnn.TryOpenAsync(command.CancellationToken).ConfigureAwait(false);
using var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader);
using var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false);
var results = MultiMapImpl(null, default, types, map, splitOn, reader, identity, true);
var results = MultiMapImpl(null, CommandDefinition.ForCallback(command.Parameters, command.Flags), types, map, splitOn, reader, identity, true, info);
return command.Buffered ? results.ToList() : results;
}
finally
Expand Down
8 changes: 4 additions & 4 deletions Dapper/SqlMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,11 +1584,11 @@ private static IEnumerable<TReturn> MultiMap<TFirst, TSecond, TThird, TFourth, T
return buffered ? results.ToList() : results;
}

private static IEnumerable<TReturn> MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection? cnn, CommandDefinition command, Delegate map, string splitOn, DbDataReader? 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, DbDataReader? reader, Identity? identity, bool finalize, CacheInfo? cacheInfo = null)
{
object? param = command.Parameters;
identity ??= new Identity<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh>(command.CommandText, command.CommandTypeDirect, cnn!, typeof(TFirst), param?.GetType());
CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);
CacheInfo cinfo = cacheInfo ?? GetCacheInfo(identity, param, command.AddToCache);

IDbCommand? ownedCommand = null;
DbDataReader? ownedReader = null;
Expand Down Expand Up @@ -1650,7 +1650,7 @@ private static CommandBehavior GetBehavior(bool close, CommandBehavior @default)
return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors;
}

private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection? cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, DbDataReader? reader, Identity? identity, bool finalize)
private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection? cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, DbDataReader? reader, Identity? identity, bool finalize, CacheInfo? cacheInfo = null)
{
if (types.Length < 1)
{
Expand All @@ -1659,7 +1659,7 @@ private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection? cn

object? param = command.Parameters;
identity ??= new IdentityWithTypes(command.CommandText, command.CommandTypeDirect, cnn!, types[0], param?.GetType(), types);
CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);
CacheInfo cinfo = cacheInfo ?? GetCacheInfo(identity, param, command.AddToCache);

IDbCommand? ownedCommand = null;
DbDataReader? ownedReader = null;
Expand Down
46 changes: 46 additions & 0 deletions tests/Dapper.Tests/Providers/SqliteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,51 @@ private class PersonWithDob
public int Id { get; set; }
public DateTime DoB { get; set; }
}

[FactSqlite]
public async Task Issue2240_MultiMapAsync_CacheHitAccounting()
{
using var connection = GetSQLiteConnection();
SqlMapper.PurgeQueryCache();

var sqlGeneric = "SELECT 1 AS Id, 'Alice' AS Name, 2 AS ExtraId, 'Bob' AS ExtraName WHERE 0 /* issue2240_generic */";
await connection.QueryAsync<HazNameId, HazNameId, int>(
sqlGeneric,
(a, b) => a.Id + b.Id,
splitOn: "ExtraId").ConfigureAwait(false);

var genericHits = SqlMapper.GetCachedSQL().Single(x => x.Item2 == sqlGeneric).Item3;
Assert.Equal(0, genericHits);

// Second execution of the same query should count as reuse (hit count 1)
await connection.QueryAsync<HazNameId, HazNameId, int>(
sqlGeneric,
(a, b) => a.Id + b.Id,
splitOn: "ExtraId").ConfigureAwait(false);

genericHits = SqlMapper.GetCachedSQL().Single(x => x.Item2 == sqlGeneric).Item3;
Assert.Equal(1, genericHits);

var sqlTypes = "SELECT 1 AS Id, 'Alice' AS Name, 2 AS ExtraId, 'Bob' AS ExtraName WHERE 0 /* issue2240_types */";
await connection.QueryAsync<int>(
sqlTypes,
new[] { typeof(HazNameId), typeof(HazNameId) },
objs => ((HazNameId)objs[0]).Id + ((HazNameId)objs[1]).Id,
splitOn: "ExtraId").ConfigureAwait(false);

var typesHits = SqlMapper.GetCachedSQL().Single(x => x.Item2 == sqlTypes).Item3;
Assert.Equal(0, typesHits);

// Second execution of the same query should count as reuse (hit count 1)
await connection.QueryAsync<int>(
sqlTypes,
new[] { typeof(HazNameId), typeof(HazNameId) },
objs => ((HazNameId)objs[0]).Id + ((HazNameId)objs[1]).Id,
splitOn: "ExtraId").ConfigureAwait(false);

typesHits = SqlMapper.GetCachedSQL().Single(x => x.Item2 == sqlTypes).Item3;
Assert.Equal(1, typesHits);
}
}
}