Weiß jemand, ob es möglich ist, tabellenwertige Parameterdaten mit Dapper an eine gespeicherte Prozedur zu übergeben?
Weiß jemand, ob es möglich ist, tabellenwertige Parameterdaten mit Dapper an eine gespeicherte Prozedur zu übergeben?
Antworten:
Es gibt jetzt (n Dapper 1.26 und höher) direkte Unterstützung für in dapper eingebrannte tabellenwertige Parameter. Bei gespeicherten Prozeduren müssen Sie, da der Datentyp in die sproc-API integriert ist, lediglich Folgendes angeben DataTable
:
var data = connection.Query<SomeType>(..., new {
id=123, name="abc", values = someTable
}, ...);
Für direkten Befehlstext haben Sie zwei weitere Möglichkeiten:
Verwenden Sie eine Hilfsmethode, um den benutzerdefinierten Datentyp anzugeben:
var data = connection.Query<SomeType>(..., new {
id=123, name="abc", values = someTable.AsTableValuedParameter("mytype")
}, ...);
Teilen Sie der Datentabelle selbst mit, welcher benutzerdefinierte Datentyp verwendet werden soll:
someTable.SetTypeName("mytype");
var data = connection.Query<SomeType>(..., new {
id=123, name="abc", values = someTable
}, ...);
Jedes davon sollte gut funktionieren.
ExecuteReader
erhalte ich "Die Mitgliedsereignisse vom Typ System.Data.DataTable können nicht als Parameterwert verwendet werden".
Ja, wir unterstützen sie, aber Sie müssen Ihre eigenen Helfer codieren.
Zum Beispiel:
class IntDynamicParam : Dapper.SqlMapper.IDynamicParameters
{
IEnumerable<int> numbers;
public IntDynamicParam(IEnumerable<int> numbers)
{
this.numbers = numbers;
}
public void AddParameters(IDbCommand command)
{
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("@ints", SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
p.TypeName = "int_list_type";
p.Value = number_list;
}
}
// SQL Server specific test to demonstrate TVP
public void TestTVP()
{
try
{
connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
connection.Execute("CREATE PROC get_ints @ints int_list_type READONLY AS select * from @ints");
var nums = connection.Query<int>("get_ints", new IntDynamicParam(new int[] { 1, 2, 3 })).ToList();
nums[0].IsEqualTo(1);
nums[1].IsEqualTo(2);
nums[2].IsEqualTo(3);
nums.Count.IsEqualTo(3);
connection.Execute("DROP PROC get_ints");
connection.Execute("DROP TYPE int_list_type");
}
}
Stellen Sie sicher, dass Sie die Leistung für Parameter mit Tabellenwerten ordnungsgemäß testen. Als ich dies zum Übergeben von int-Listen getestet habe, war es erheblich langsamer als das Übergeben mehrerer Parameter.
Ich bin absolut nicht dagegen, einige SQL Server-spezifische Helfer für Dapper im Contrib-Projekt zu haben, aber der Core-Dapper vermeidet es, wenn möglich herstellerspezifische Tricks hinzuzufügen.
Ich weiß, dass dieses Ticket ALT ist, sehr alt, aber ich wollte Sie wissen lassen, dass ich das Dapper.Microsoft.Sql-Paket veröffentlicht habe, das generische TVPs unterstützt.
https://www.nuget.org/packages/Dapper.Microsoft.Sql/
Beispielverwendung:
List<char> nums = this.connection.Query<char>(
"get_ints",
new TableValuedParameter<char>(
"@ints", "int_list_Type", new[] { 'A', 'B', 'C' })).ToList();
Es basiert auf den ursprünglichen Klassen aus dem Dapper-Testprojekt.
Genießen!
heute ist es nicht. Wir haben tatsächlich tabellenwertige Parameter für unsere freche "in" -Implementierung ( where col in @values
) untersucht, waren jedoch von der Leistung sehr unbeeindruckt. Im Kontext eines SPROC ist dies jedoch sinnvoll.
Am besten protokollieren Sie dies als Problem auf der Projektwebsite, damit wir es verfolgen / priorisieren können. Es hört sich jedoch so an, als wäre etwas machbar, wahrscheinlich ähnlich wie bei den Optionen DbString oder DynamicParameters.
Aber heute? Nein.