diff --git a/Dapper/DynamicParameters.cs b/Dapper/DynamicParameters.cs
index f6708b5ce..e0f707b96 100644
--- a/Dapper/DynamicParameters.cs
+++ b/Dapper/DynamicParameters.cs
@@ -305,7 +305,7 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
///
/// All the names of the param in the bag, use Get to yank them out
///
- public IEnumerable ParameterNames => parameters.Select(p => p.Key);
+ public IEnumerable ParameterNames => GetParamNames();
///
/// Get the value of a parameter
@@ -315,18 +315,41 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
/// The value, note DBNull.Value is not returned, instead the value is returned as null
public T Get(string name)
{
- var paramInfo = parameters[Clean(name)];
- var attachedParam = paramInfo.AttachedParam;
- object? val = attachedParam is null ? paramInfo.Value : attachedParam.Value;
- if (val == DBNull.Value)
+ var cleanName = Clean(name);
+ if (parameters.TryGetValue(cleanName, out var paramInfo))
{
- if (default(T) is not null)
+ object? val = paramInfo!.AttachedParam is null ? paramInfo.Value : paramInfo.AttachedParam.Value;
+ if (val == DBNull.Value)
{
- throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
+ if (default(T) is not null)
+ {
+ throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
+ }
+ return default!;
}
- return default!;
+ return (T)val!;
}
- return (T)val!;
+ if (templates != null)
+ {
+ var foundValue = templates
+ .Select(obj => obj?.GetType().GetProperty(cleanName)?.GetValue(obj))
+ .FirstOrDefault(value => value != null);
+
+ if (foundValue != null)
+ {
+ if (foundValue == DBNull.Value)
+ {
+ if (default(T) is not null)
+ {
+ throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
+ }
+ return default!;
+ }
+ return (T)foundValue;
+ }
+ }
+
+ throw new KeyNotFoundException($"Key {name} could not be found in param list.");
}
///
@@ -496,5 +519,18 @@ void SqlMapper.IParameterCallbacks.OnCompleted()
param.OutputCallback?.Invoke(param.OutputTarget, this);
}
}
+ private List GetParamNames()
+ {
+ var paramBagItems = parameters.Select(p => p.Key);
+ var propNames = new List();
+ if(templates != null)
+ {
+ var templateProps = templates.SelectMany(obj => obj.GetType().GetProperties());
+ propNames.AddRange(templateProps.Select(prop => prop.Name).Distinct());
+ }
+
+ propNames.AddRange(paramBagItems);
+ return propNames;
+ }
}
}
diff --git a/tests/Dapper.Tests/ParameterTests.cs b/tests/Dapper.Tests/ParameterTests.cs
index 650624c20..61dde978b 100644
--- a/tests/Dapper.Tests/ParameterTests.cs
+++ b/tests/Dapper.Tests/ParameterTests.cs
@@ -376,6 +376,68 @@ public void TestTVP()
}
}
}
+ [Fact]
+ public void TestGetSqlBuilderParamNames()
+ {
+ var sqlBuilder = new SqlBuilder();
+
+ var templateA = sqlBuilder.AddTemplate("SELECT @a", new
+ {
+ a = 1
+ });
+ var templateB = sqlBuilder.AddTemplate("SELECT @b", new
+ {
+ b = 2
+ });
+ sqlBuilder.AddParameters(new
+ {
+ c = 3
+ });
+
+ var aParameters = new DynamicParameters(templateA.Parameters);
+ var aParamNames = aParameters.ParameterNames;
+
+ var bParameters = new DynamicParameters(templateB.Parameters);
+ var bParamNames = bParameters.ParameterNames;
+
+ Assert.Contains("a", aParamNames);
+ Assert.DoesNotContain("b", aParamNames);
+ Assert.Contains("c", aParamNames);
+ Assert.DoesNotContain("a", bParamNames);
+ Assert.Contains("b", bParamNames);
+ Assert.Contains("c", bParamNames);
+ }
+ [Fact]
+ public void TestGetSqlBuilderParams()
+ {
+ var sqlBuilder = new SqlBuilder();
+
+ var templateA = sqlBuilder.AddTemplate("SELECT @a", new
+ {
+ a = 1
+ });
+ var templateB = sqlBuilder.AddTemplate("SELECT @b", new
+ {
+ b = 2
+ });
+ sqlBuilder.AddParameters(new
+ {
+ c = 3
+ });
+
+ var aParameters = new DynamicParameters(templateA.Parameters);
+ var bParameters = new DynamicParameters(templateB.Parameters);
+
+ var aParamValue = aParameters.Get("a");
+ var bParamValue = bParameters.Get("b");
+ var cParamValueA = aParameters.Get("c");
+ var cParamValueB = bParameters.Get("c");
+
+ Assert.Equal(1, aParamValue);
+ Assert.Equal(2, bParamValue);
+ Assert.Equal(3, cParamValueA);
+ Assert.Equal(3, cParamValueB);
+ }
private class DynamicParameterWithIntTVP : DynamicParameters, SqlMapper.IDynamicParameters
{