From 2c5a165dab689c41d0a8b97d076a0f5808720fbf Mon Sep 17 00:00:00 2001 From: nandan Date: Sat, 27 Sep 2025 01:46:30 +0530 Subject: [PATCH 1/2] Refactor GridReader parameter type from DynamicParameters to IParameterCallbacks and add tests for QueryMultiple and QueryMultipleAsync to verify OnCompleted behavior. --- Dapper/SqlMapper.Async.cs | 2 +- Dapper/SqlMapper.cs | 2 +- .../Dapper.Tests/IParameterCallbacksTests.cs | 64 +++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/Dapper.Tests/IParameterCallbacksTests.cs 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..e04ec61dd --- /dev/null +++ b/tests/Dapper.Tests/IParameterCallbacksTests.cs @@ -0,0 +1,64 @@ +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) + { + // nothing needed here for this test + } + + public void OnCompleted() + { + Completed = true; + } + } + + [Fact] + public void QueryMultiple_Calls_OnCompleted() + { + using var connection = GetOpenConnection(); + 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() + { + using var connection = GetOpenConnection(); + 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 IDbConnection GetOpenConnection() + { + // Please note that CI usually has a test DB so please adjust connection string as required + var cs = "Server=localhost,1433;User Id=sa;Password=Str0ngPassw0rd!;TrustServerCertificate=true;"; + var connection = new SqlConnection(cs); + connection.Open(); + return connection; + } + } +} From 8d7ec6413b8b4337d309692e837cba9e47e31ec6 Mon Sep 17 00:00:00 2001 From: nandan Date: Sat, 27 Sep 2025 02:32:23 +0530 Subject: [PATCH 2/2] Refactor IParameterCallbacksTests to improve connection handling which was failing in AppVeyor. --- .../Dapper.Tests/IParameterCallbacksTests.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/tests/Dapper.Tests/IParameterCallbacksTests.cs b/tests/Dapper.Tests/IParameterCallbacksTests.cs index e04ec61dd..66af1de47 100644 --- a/tests/Dapper.Tests/IParameterCallbacksTests.cs +++ b/tests/Dapper.Tests/IParameterCallbacksTests.cs @@ -13,19 +13,17 @@ class TestParams : SqlMapper.IDynamicParameters, SqlMapper.IParameterCallbacks public void AddParameters(IDbCommand command, SqlMapper.Identity identity) { - // nothing needed here for this test + // no params needed } - public void OnCompleted() - { - Completed = true; - } + public void OnCompleted() => Completed = true; } [Fact] public void QueryMultiple_Calls_OnCompleted() { - using var connection = GetOpenConnection(); + if (!TryOpenConnection(out var conn)) return; + using var connection = conn!; var p = new TestParams(); using (var grid = connection.QueryMultiple("select 1; select 2;", p)) @@ -40,7 +38,8 @@ public void QueryMultiple_Calls_OnCompleted() [Fact] public async Task QueryMultipleAsync_Calls_OnCompleted() { - using var connection = GetOpenConnection(); + 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)) @@ -52,13 +51,21 @@ public async Task QueryMultipleAsync_Calls_OnCompleted() Assert.True(p.Completed); } - private static IDbConnection GetOpenConnection() + private static bool TryOpenConnection(out IDbConnection? connection) { - // Please note that CI usually has a test DB so please adjust connection string as required - var cs = "Server=localhost,1433;User Id=sa;Password=Str0ngPassw0rd!;TrustServerCertificate=true;"; - var connection = new SqlConnection(cs); - connection.Open(); - return 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; + } } } }