Commit 6815c6f0 authored by Fabian de Groot's avatar Fabian de Groot

Added support for TVP in anonymous objects

parent 36f51540
......@@ -33,5 +33,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.12.0.0")]
[assembly: AssemblyFileVersion("1.12.0.0")]
[assembly: AssemblyVersion("1.12.1.1")]
[assembly: AssemblyFileVersion("1.12.1.1")]
......@@ -40,6 +40,19 @@ public partial interface IDynamicParameters
void AddParameters(IDbCommand command, Identity identity);
}
/// <summary>
/// Implement this interface to pass an arbitrary db specific parameter to Dapper
/// </summary>
public interface ICustomQueryParameter
{
/// <summary>
/// Add the parameter needed to the command before it executes
/// </summary>
/// <param name="command">The raw command prior to execution</param>
/// <param name="name">Parameter name</param>
void AddParameter(IDbCommand command, string name);
}
/// <summary>
/// Implement this interface to change default mapping of reader columns to type memebers
/// </summary>
......@@ -1757,13 +1770,13 @@ private static IEnumerable<PropertyInfo> FilterParameters(IEnumerable<PropertyIn
continue;
}
}
if (prop.PropertyType == typeof(DbString))
if (typeof(ICustomQueryParameter).IsAssignableFrom(prop.PropertyType))
{
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [typed-param]
il.Emit(OpCodes.Callvirt, prop.GetGetMethod()); // stack is [parameters] [dbstring]
il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [dbstring] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [dbstring] [command] [name]
il.EmitCall(OpCodes.Callvirt, typeof(DbString).GetMethod("AddParameter"), null); // stack is now [parameters]
il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod("AddParameter"), null); // stack is now [parameters]
continue;
}
DbType dbType = LookupDbType(prop.PropertyType, prop.Name);
......@@ -2949,7 +2962,7 @@ public T Get<T>(string name)
/// <summary>
/// This class represents a SQL string, it can be used if you need to denote your parameter is a Char vs VarChar vs nVarChar vs nChar
/// </summary>
sealed partial class DbString
sealed partial class DbString : Dapper.SqlMapper.ICustomQueryParameter
{
/// <summary>
/// Create a new DbString
......
......@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata schemaVersion="2">
<id>Dapper</id>
<version>1.12.1</version>
<version>1.12.1.1</version>
<title>Dapper dot net</title>
<authors>Sam Saffron,Marc Gravell</authors>
<owners>Sam Saffron,Marc Gravell</owners>
......@@ -19,6 +19,7 @@
<frameworkAssembly assemblyName="Microsoft.CSharp" targetFramework=".NETFramework4.0-Client, .NETFramework4.0" />
</frameworkAssemblies>
<releaseNotes>
* 1.12.1.1 - Added support for Table Valued Parameters as part of anonymous objects
* 1.12.1 - Minor deploy glitch (should now include intellisense files!)
* 1.12 - Better automatic type-mapping (int vs long, float vs double, etc)
* Fixed: bug with indexer properties
......
......@@ -1331,6 +1331,67 @@ public void TestTVPWithAdditionalParams()
}
}
class IntCustomParam : Dapper.SqlMapper.ICustomQueryParameter
{
IEnumerable<int> numbers;
public IntCustomParam(IEnumerable<int> numbers)
{
this.numbers = numbers;
}
public void AddParameter(IDbCommand command, string name)
{
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>();
// Create an SqlMetaData object that describes our table type.
Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
foreach (int n in numbers)
{
// Create a new record, using the metadata array above.
Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
rec.SetInt32(0, n); // Set the value.
number_list.Add(rec); // Add it to the list.
}
// Add the table parameter.
var p = sqlCommand.Parameters.Add(name, SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
p.TypeName = "int_list_type";
p.Value = number_list;
}
}
public void TestTVPWithAnonymousObject()
{
try
{
connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
connection.Execute("CREATE PROC get_ints @integers int_list_type READONLY AS select * from @integers");
var nums = connection.Query<int>("get_ints", new { integers = new IntCustomParam(new int[] { 1, 2, 3 }) }, commandType: CommandType.StoredProcedure).ToList();
nums[0].IsEqualTo(1);
nums[1].IsEqualTo(2);
nums[2].IsEqualTo(3);
nums.Count.IsEqualTo(3);
}
finally
{
try
{
connection.Execute("DROP PROC get_ints");
}
finally
{
connection.Execute("DROP TYPE int_list_type");
}
}
}
class Parent
{
public int Id { get; set; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment