diff --git a/Dapper/SqlMapper.Async.cs b/Dapper/SqlMapper.Async.cs index eade08cb2..4e71a2210 100644 --- a/Dapper/SqlMapper.Async.cs +++ b/Dapper/SqlMapper.Async.cs @@ -940,7 +940,7 @@ private static async Task> MultiMapAsync(null, CommandDefinition.ForCallback(command.Parameters, command.Flags), map, splitOn, reader, identity, true); + var results = MultiMapImpl(null, CommandDefinition.ForCallback(command.Parameters, command.Flags), map, splitOn, reader, identity, true, info); return command.Buffered ? results.ToList() : results; } finally @@ -988,7 +988,7 @@ private static async Task> MultiMapAsync(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, default, types, map, splitOn, reader, identity, true, info); return command.Buffered ? results.ToList() : results; } finally diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index 8f3956cab..dad971755 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -1584,11 +1584,11 @@ private static IEnumerable MultiMap MultiMapImpl(this IDbConnection? cnn, CommandDefinition command, Delegate map, string splitOn, DbDataReader? reader, Identity? identity, bool finalize) + private static IEnumerable MultiMapImpl(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(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; @@ -1650,7 +1650,7 @@ private static CommandBehavior GetBehavior(bool close, CommandBehavior @default) return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors; } - private static IEnumerable MultiMapImpl(this IDbConnection? cnn, CommandDefinition command, Type[] types, Func map, string splitOn, DbDataReader? reader, Identity? identity, bool finalize) + private static IEnumerable MultiMapImpl(this IDbConnection? cnn, CommandDefinition command, Type[] types, Func map, string splitOn, DbDataReader? reader, Identity? identity, bool finalize, CacheInfo? cacheInfo = null) { if (types.Length < 1) { @@ -1659,7 +1659,7 @@ private static IEnumerable MultiMapImpl(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; diff --git a/Directory.Packages.props b/Directory.Packages.props index 2f91a3cca..b1e42ba41 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -38,6 +38,7 @@ + diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj index 93b498618..e9eab6b88 100644 --- a/tests/Dapper.Tests/Dapper.Tests.csproj +++ b/tests/Dapper.Tests/Dapper.Tests.csproj @@ -32,6 +32,7 @@ + diff --git a/tests/Dapper.Tests/FakeDbTests.Issue2240.cs b/tests/Dapper.Tests/FakeDbTests.Issue2240.cs new file mode 100644 index 000000000..c453609e3 --- /dev/null +++ b/tests/Dapper.Tests/FakeDbTests.Issue2240.cs @@ -0,0 +1,42 @@ +#if !NET481 +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using pengdows.crud.fakeDb; +using Xunit; + +namespace Dapper.Tests; + +public sealed class FakeDbIssue2240Tests +{ + [Fact] + public async Task FirstAsyncMultiMapExecutionDoesNotRecordSyntheticCacheHit() + { + SqlMapper.PurgeQueryCache(); + using var connection = new fakeDbConnection(new FakeDataStore()); + connection.EnqueueReaderResult(new[] + { + new Dictionary + { + ["A"] = 1, + ["B"] = 2, + ["C"] = 3, + }, + }); + connection.Open(); + + await connection.QueryAsync( + "select 1 as A, 2 as B, 3 as C", + (a, b, c) => a.A + b.B + c.C, + splitOn: "B,C"); + + var cached = SqlMapper.GetCachedSQL().ToList(); + Assert.NotEmpty(cached); + Assert.Equal(0, cached.Single().Item3); + } + + private sealed class First { public int A { get; set; } } + private sealed class Second { public int B { get; set; } } + private sealed class Third { public int C { get; set; } } +} +#endif