Skip to content
Merged
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
16 changes: 16 additions & 0 deletions Dapper/DynamicParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,22 @@ void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Id
AddParameters(command, identity);
}

/// <summary>
/// Add all the parameters needed to the command just before it executes, using the
/// command's own text and type for any query-specific handling (literal tokens, etc);
/// this allows external tooling (for example build-time code generators) to apply a
/// parameter bag without constructing an <see cref="SqlMapper.Identity"/>
/// </summary>
/// <param name="command">The raw command prior to execution</param>
public void AddParameters(IDbCommand command)
{
if (command is null) throw new ArgumentNullException(nameof(command));
// dispatch via the interface so that a subclass which hides AddParameters and
// re-implements IDynamicParameters (an established extension pattern) still runs
((SqlMapper.IDynamicParameters)this).AddParameters(command, new SqlMapper.Identity(
command.CommandText, command.CommandType, command.Connection!, null, GetType()));
}

/// <summary>
/// If true, the command-text is inspected and only values that are clearly used are included on the connection
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion Dapper/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#nullable enable
static Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums.get -> bool
static Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums.set -> void
static Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums.set -> void
Dapper.DynamicParameters.AddParameters(System.Data.IDbCommand! command) -> void
49 changes: 49 additions & 0 deletions tests/Dapper.Tests/ParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,55 @@ public void TestDynamicParamNullSupport()
Assert.Null(p.Get<int?>("@b"));
}

[Fact]
public void AddParameters_Command_AppliesBagAndLiterals()
{
// the identity-free overload: external tooling (e.g. build-time code generators)
// can apply a bag using the command's own text for query-specific handling
using var connection = GetClosedConnection();
using var command = connection.CreateCommand();
command.CommandText = "select @a + {=b}";

var args = new DynamicParameters();
args.Add("a", 1);
args.Add("b", 2);
args.AddParameters(command);

Assert.Equal("select @a + 2", command.CommandText); // literal replaced
// (note the literal member is still attached as a parameter too - unused, but
// that matches what the bag does under vanilla execution)
var p = Assert.IsAssignableFrom<IDbDataParameter>(command.Parameters[0]);
Assert.Equal("a", p.ParameterName);
Assert.Equal(1, p.Value);
Assert.Equal(2, command.Parameters.Count);
}

[Fact]
public void AddParameters_Command_DispatchesViaInterface()
{
// a subclass that hides AddParameters and re-implements IDynamicParameters
// (the DynamicParameterWithIntTVP pattern) must still get its version called
using var connection = GetClosedConnection();
using var command = connection.CreateCommand();
command.CommandText = "select @a";

var args = new HidingBag();
args.Add("a", 1);
args.AddParameters(command);

Assert.True(args.CustomRan);
}

private class HidingBag : DynamicParameters, SqlMapper.IDynamicParameters
{
public bool CustomRan { get; private set; }
public new void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
base.AddParameters(command, identity);
CustomRan = true;
}
}

[Fact]
public void TestAppendingAnonClasses()
{
Expand Down
Loading