diff --git a/Dapper/SqlMapper.Async.cs b/Dapper/SqlMapper.Async.cs index eade08cb2..c6377257c 100644 --- a/Dapper/SqlMapper.Async.cs +++ b/Dapper/SqlMapper.Async.cs @@ -1042,7 +1042,7 @@ public static async Task QueryMultipleAsync(this IDbConnection cnn, cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader); reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false); - var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache, command.CancellationToken); + var result = new GridReader(cmd, reader, identity, command.Parameters as IParameterCallbacks, command.AddToCache, command.CancellationToken); wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader // with the CloseConnection flag, so the reader will deal with the connection; we // still need something in the "finally" to ensure that broken SQL still results diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index d23e949a5..b6e321951 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -1151,7 +1151,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD cmd = command.SetupCommand(cnn, info.ParamReader); reader = ExecuteReaderWithFlagsFallback(cmd, wasClosed, CommandBehavior.SequentialAccess); - var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache); + var result = new GridReader(cmd, reader, identity, command.Parameters as IParameterCallbacks, command.AddToCache); cmd = null; // now owned by result wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader // with the CloseConnection flag, so the reader will deal with the connection; we diff --git a/tests/Dapper.Tests/IParameterCallbacksTests.cs b/tests/Dapper.Tests/IParameterCallbacksTests.cs new file mode 100644 index 000000000..66af1de47 --- /dev/null +++ b/tests/Dapper.Tests/IParameterCallbacksTests.cs @@ -0,0 +1,71 @@ +using System.Data; +using System.Threading.Tasks; +using Microsoft.Data.SqlClient; +using Xunit; + +namespace Dapper.Tests +{ + public class IParameterCallbacksTests + { + class TestParams : SqlMapper.IDynamicParameters, SqlMapper.IParameterCallbacks + { + public bool Completed { get; private set; } + + public void AddParameters(IDbCommand command, SqlMapper.Identity identity) + { + // no params needed + } + + public void OnCompleted() => Completed = true; + } + + [Fact] + public void QueryMultiple_Calls_OnCompleted() + { + if (!TryOpenConnection(out var conn)) return; + using var connection = conn!; + var p = new TestParams(); + + using (var grid = connection.QueryMultiple("select 1; select 2;", p)) + { + var _ = grid.Read(); + var __ = grid.Read(); + } + + Assert.True(p.Completed); + } + + [Fact] + public async Task QueryMultipleAsync_Calls_OnCompleted() + { + if (!TryOpenConnection(out var conn)) return; + using var connection = conn!; + var p = new TestParams(); + + using (var grid = await connection.QueryMultipleAsync("select 1; select 2;", p)) + { + var _ = await grid.ReadAsync(); + var __ = await grid.ReadAsync(); + } + + Assert.True(p.Completed); + } + + private static bool TryOpenConnection(out IDbConnection? connection) + { + connection = null; + try + { + var cs = "Server=localhost,1433;User Id=sa;Password=Str0ngPassw0rd!;TrustServerCertificate=true;"; + var c = new SqlConnection(cs); + c.Open(); + connection = c; + return true; + } + catch + { + return false; + } + } + } +}