From b87d958314b1a85f52c7ef37b78d3740154b4d04 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Mon, 15 Sep 2014 11:48:14 +0100 Subject: [PATCH] Rationalize FireOutputCallbacks, and apply to remaining methods --- Dapper NET40/SqlMapper.cs | 88 +++++++++------ Dapper NET45/SqlMapperAsync.cs | 25 +++-- DapperTests NET45/Tests.cs | 194 +++++++++++++++++++++++++++++++++ Tests/Tests.cs | 123 +++++++++++++++++++++ 4 files changed, 388 insertions(+), 42 deletions(-) diff --git a/Dapper NET40/SqlMapper.cs b/Dapper NET40/SqlMapper.cs index 3571aa9..7d2f38f 100644 --- a/Dapper NET40/SqlMapper.cs +++ b/Dapper NET40/SqlMapper.cs @@ -52,8 +52,19 @@ public enum CommandFlags /// /// Represents the key aspects of a sql operation /// - public struct CommandDefinition + public struct CommandDefinition { + internal static CommandDefinition ForCallback(object parameters) + { + if(parameters is DynamicParameters) + { + return new CommandDefinition(parameters); + } + else + { + return default(CommandDefinition); + } + } private readonly string commandText; private readonly object parameters; private readonly IDbTransaction transaction; @@ -62,7 +73,13 @@ public struct CommandDefinition private readonly CommandFlags flags; - + internal void FireOutputCallbacks() + { + if (parameters is DynamicParameters) + { + ((DynamicParameters)parameters).FireOutputCallbacks(); + } + } /// /// The command (sql or a stored-procedure name) to execute /// @@ -130,6 +147,11 @@ public struct CommandDefinition #endif } + private CommandDefinition(object parameters) : this() + { + this.parameters = parameters; + } + #if ASYNC private readonly CancellationToken cancellationToken; /// @@ -1120,7 +1142,7 @@ public static GridReader QueryMultiple(this IDbConnection cnn, string sql, objec #if CSHARP30 this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1145,7 +1167,7 @@ public static int Execute(this IDbConnection cnn, CommandDefinition command) #if CSHARP30 this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1161,7 +1183,7 @@ public static int Execute(this IDbConnection cnn, CommandDefinition command) #if CSHARP30 this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1229,6 +1251,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com total += cmd.ExecuteNonQuery(); } } + command.FireOutputCallbacks(); } finally { if (wasClosed) cnn.Close(); @@ -1268,7 +1291,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com #if CSHARP30 this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1305,7 +1328,7 @@ public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinitio /// /// Return a list of dynamic objects, reader is closed after the call /// - public static IEnumerable Query(this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) + public static IEnumerable Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) { return Query(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType); } @@ -1362,7 +1385,7 @@ public static IEnumerable Query(this IDbConnection cnn, string sql, dyn #if CSHARP30 this IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1412,7 +1435,7 @@ public static IEnumerable Query(this IDbConnection cnn, CommandDefinition #if CSHARP30 this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType #else - this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null + this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1441,7 +1464,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD cmd = command.SetupCommand(cnn, info.ParamReader); reader = cmd.ExecuteReader(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess); - var result = new GridReader(cmd, reader, identity); + var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters); 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 @@ -1503,10 +1526,13 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture); } } + while (reader.NextResult()) { } // happy path; close the reader cleanly - no // need for "Cancel" etc reader.Dispose(); reader = null; + + command.FireOutputCallbacks(); } finally { @@ -1541,7 +1567,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini #if CSHARP30 this IDbConnection cnn, string sql, Func map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1569,7 +1595,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini #if CSHARP30 this IDbConnection cnn, string sql, Func map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1598,7 +1624,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini #if CSHARP30 this IDbConnection cnn, string sql, Func map, object param, IDbTransaction transaction, bool buffered, string splitOn, int? commandTimeout, CommandType? commandType #else -this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null +this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null #endif ) { @@ -1626,7 +1652,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini /// /// public static IEnumerable Query( - this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null + this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null ) { return MultiMap(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType); @@ -1653,7 +1679,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini /// /// public static IEnumerable Query( - this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null + this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null ) { return MultiMap(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType); @@ -1681,7 +1707,7 @@ private static IEnumerable QueryImpl(this IDbConnection cnn, CommandDefini /// /// /// - public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) + public static IEnumerable Query(this IDbConnection cnn, string sql, Func map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) { return MultiMap(cnn, sql, map, param as object, transaction, buffered, splitOn, commandTimeout, commandType); } @@ -1734,6 +1760,7 @@ partial class DontMap { } { yield return mapIt(reader); } + command.FireOutputCallbacks(); } } finally @@ -3022,17 +3049,14 @@ private static int ExecuteCommand(IDbConnection cnn, ref CommandDefinition comma { cmd = command.SetupCommand(cnn, paramReader); if (wasClosed) cnn.Open(); - return cmd.ExecuteNonQuery(); + int result = cmd.ExecuteNonQuery(); + command.FireOutputCallbacks(); + return result; } finally { if (wasClosed) cnn.Close(); if (cmd != null) cmd.Dispose(); - - if (command.Parameters is DynamicParameters) - { - ((DynamicParameters)command.Parameters).FireOutputCallbacks(); - } } } @@ -3054,16 +3078,12 @@ private static T ExecuteScalarImpl(IDbConnection cnn, ref CommandDefinition c cmd = command.SetupCommand(cnn, paramReader); if (wasClosed) cnn.Open(); result =cmd.ExecuteScalar(); + command.FireOutputCallbacks(); } finally { if (wasClosed) cnn.Close(); if (cmd != null) cmd.Dispose(); - - if (command.Parameters is DynamicParameters) - { - ((DynamicParameters)command.Parameters).FireOutputCallbacks(); - } } return Parse(result); } @@ -3081,17 +3101,14 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin if (wasClosed) commandBehavior |= CommandBehavior.CloseConnection; var reader = cmd.ExecuteReader(commandBehavior); wasClosed = false; // don't dispose before giving it to them! + + // note: command.FireOutputCallbacks(); would be useless here; parameters come at the **end** of the TDS stream return reader; } finally { if (wasClosed) cnn.Close(); if (cmd != null) cmd.Dispose(); - - if (command.Parameters is DynamicParameters) - { - ((DynamicParameters)command.Parameters).FireOutputCallbacks(); - } } } @@ -3785,11 +3802,12 @@ public partial class GridReader : IDisposable private IDbCommand command; private Identity identity; - internal GridReader(IDbCommand command, IDataReader reader, Identity identity) + internal GridReader(IDbCommand command, IDataReader reader, Identity identity, DynamicParameters dynamicParams) { this.command = command; this.reader = reader; this.identity = identity; + this.dynamicParams = dynamicParams; } #if !CSHARP30 @@ -3996,6 +4014,8 @@ private IEnumerable ReadDeferred(int index, Func dese } private int gridIndex, readCount; private bool consumed; + private DynamicParameters dynamicParams; + /// /// Has the underlying reader been consumed? /// @@ -4020,7 +4040,7 @@ private void NextResult() // need for "Cancel" etc reader.Dispose(); reader = null; - + if (dynamicParams != null) dynamicParams.FireOutputCallbacks(); Dispose(); } } diff --git a/Dapper NET45/SqlMapperAsync.cs b/Dapper NET45/SqlMapperAsync.cs index 5885836..b2d672f 100644 --- a/Dapper NET45/SqlMapperAsync.cs +++ b/Dapper NET45/SqlMapperAsync.cs @@ -95,13 +95,15 @@ private static async Task> QueryAsync(this IDbConnection cnn, { buffer.Add((T)func(reader)); } + while (await reader.NextResultAsync().ConfigureAwait(false)) { } + command.FireOutputCallbacks(); return buffer; } else { // can't use ReadAsync / cancellation; but this will have to do wasClosed = false; // don't close if handing back an open reader; rely on the command-behavior - var deferred = ExecuteReaderSync(reader, func); + var deferred = ExecuteReaderSync(reader, func, command.Parameters); reader = null; // to prevent it being disposed before the caller gets to see it return deferred; } @@ -211,7 +213,6 @@ private static async Task ExecuteMultiImplAsync(IDbConnection cnn, CommandD using (pending.Dequeue().Command) { } // dispose commands } } - return total; } else { @@ -236,6 +237,8 @@ private static async Task ExecuteMultiImplAsync(IDbConnection cnn, CommandD } } } + + command.FireOutputCallbacks(); } finally { @@ -253,7 +256,9 @@ private static async Task ExecuteImplAsync(IDbConnection cnn, CommandDefini try { if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); - return await cmd.ExecuteNonQueryAsync(command.CancellationToken).ConfigureAwait(false); + var result = await cmd.ExecuteNonQueryAsync(command.CancellationToken).ConfigureAwait(false); + command.FireOutputCallbacks(); + return result; } finally { @@ -446,7 +451,7 @@ private static async Task ExecuteImplAsync(IDbConnection cnn, CommandDefini using (var reader = await cmd.ExecuteReaderAsync(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false)) { if (!command.Buffered) wasClosed = false; // handing back open reader; rely on command-behavior - var results = MultiMapImpl(null, default(CommandDefinition), map, splitOn, reader, identity); + var results = MultiMapImpl(null, CommandDefinition.ForCallback(command.Parameters), map, splitOn, reader, identity); return command.Buffered ? results.ToList() : results; } } finally @@ -455,12 +460,15 @@ private static async Task ExecuteImplAsync(IDbConnection cnn, CommandDefini } } - private static IEnumerable ExecuteReaderSync(IDataReader reader, Func func) + private static IEnumerable ExecuteReaderSync(IDataReader reader, Func func, object parameters) { while (reader.Read()) { yield return (T)func(reader); } + while (reader.NextResult()) { } + if (parameters is DynamicParameters) + ((DynamicParameters)parameters).FireOutputCallbacks(); } /// @@ -481,7 +489,7 @@ private static IEnumerable ExecuteReaderSync(IDataReader reader, Func QueryMultipleAsync(this IDbConnection cnn, cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader); reader = await cmd.ExecuteReaderAsync(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false); - var result = new GridReader(cmd, reader, identity, command.CancellationToken); + var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, 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 @@ -758,6 +766,7 @@ private async static Task ExecuteScalarImplAsync(IDbConnection cnn, Comman cmd = (DbCommand)command.SetupCommand(cnn, paramReader); if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); result = await cmd.ExecuteScalarAsync(command.CancellationToken).ConfigureAwait(false); + command.FireOutputCallbacks(); } finally { diff --git a/DapperTests NET45/Tests.cs b/DapperTests NET45/Tests.cs index a6604bc..2abcb06 100644 --- a/DapperTests NET45/Tests.cs +++ b/DapperTests NET45/Tests.cs @@ -355,5 +355,199 @@ public void Issue22_ExecuteScalar() k.IsNull(); } } + + public void TestSupportForDynamicParametersOutputExpressions() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + connection.ExecuteAsync(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId", p).Wait(); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + } + } + public void TestSupportForDynamicParametersOutputExpressions_Scalar() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = (int)connection.ExecuteScalarAsync(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p).Result; + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_Query_Default() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = connection.QueryAsync(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p).Result.Single(); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_Query_Buffered() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = connection.QueryAsync(new CommandDefinition(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p, flags: CommandFlags.Buffered)).Result.Single(); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_Query_NonBuffered() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = connection.QueryAsync(new CommandDefinition(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p, flags: CommandFlags.None)).Result.Single(); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_QueryMultiple() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + int x, y; + using(var multi = connection.QueryMultipleAsync(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +select 42 +select 17 +SET @AddressPersonId = @PersonId", p).Result) + { + x = multi.ReadAsync().Result.Single(); + y = multi.ReadAsync().Result.Single(); + } + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + x.IsEqualTo(42); + y.IsEqualTo(17); + } + } + class Person + { + public int PersonId { get; set; } + public string Name { get; set; } + public string Occupation { get; private set; } + public int NumberOfLegs = 2; + public Address Address { get; set; } + } + class Address + { + public int AddressId { get; set; } + public string Name { get; set; } + public int PersonId { get; set; } + } } } \ No newline at end of file diff --git a/Tests/Tests.cs b/Tests/Tests.cs index 489762a..c4b44d5 100644 --- a/Tests/Tests.cs +++ b/Tests/Tests.cs @@ -1201,7 +1201,130 @@ public void TestSupportForDynamicParametersOutputExpressions() bob.Address.Name.IsEqualTo("bobs burgers"); bob.Address.PersonId.IsEqualTo(2); } + public void TestSupportForDynamicParametersOutputExpressions_Scalar() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = (int)connection.ExecuteScalar(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_Query_Buffered() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = connection.Query(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p, buffered: true).Single(); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_Query_NonBuffered() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + var result = connection.Query(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p, buffered: false).Single(); + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + result.IsEqualTo(42); + } + } + public void TestSupportForDynamicParametersOutputExpressions_QueryMultiple() + { + using (var connection = Program.GetOpenConnection()) + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address.Name); + p.Output(bob, b => b.Address.PersonId); + + int x, y; + using (var multi = connection.QueryMultiple(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +select 42 +select 17 +SET @AddressPersonId = @PersonId", p)) + { + x = multi.Read().Single(); + y = multi.Read().Single(); + } + + bob.Occupation.IsEqualTo("grillmaster"); + bob.PersonId.IsEqualTo(2); + bob.NumberOfLegs.IsEqualTo(1); + bob.Address.Name.IsEqualTo("bobs burgers"); + bob.Address.PersonId.IsEqualTo(2); + x.IsEqualTo(42); + y.IsEqualTo(17); + } + } public void TestSupportForExpandoObjectParameters() { dynamic p = new ExpandoObject(); -- GitLab