Unterstützt Dapper SQL 2008-Parameter mit Tabellenwerten?


Antworten:


91

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.


In einem Fall, in dem ich mit Dapper kein TVP hinzufügen kann, wenn ich einen Zusatz für Nicht-Eingabeparameter benötige und mit Dynamic Parameters kein TVP hinzufügen kann, überprüfen Sie bitte meine Frage @ stackoverflow.com/questions/33087629/ …
— Mrinal Kamboj

9
Bah, keine IEnumerable Konvertierung?
— Nuzzolilo

Mit ExecuteReadererhalte ich "Die Mitgliedsereignisse vom Typ System.Data.DataTable können nicht als Parameterwert verwendet werden".
— Ian Warburton

28

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.


1
Tatsächlich ist die Verwendung von TVP langsamer als "where col in @values". Wie kann ich die Listenunterstützungsfunktion (mit Dapper können Sie IEnumerable <int> übergeben und Ihre Abfrage automatisch parametrisieren) verwenden, um eine Liste von Ints an ein StoredProcedure zu übergeben?
— Carlos Mendes

Dies ist einer dieser verrückten Randfälle, in denen Stapel schneller sind als SPS. Die Technik, die Dapper für die Listenunterstützung verwendet, ist nicht mit gespeicherten Prozessen kompatibel
— Sam Saffron,

Können Sie dies aktualisieren? Ich kann nicht genau herausfinden, ob es in Ordnung ist, den Identitätsparameter in neueren Versionen von Dapper zu ignorieren.
— Chris Pfohl

Würde dieser Code so funktionieren, wie er ist, oder müsste die IEnumerable <int> -Sammlung in eine DataTable konvertiert werden, um als TVP verwendet zu werden
— Mrinal Kamboj,

11

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!


Ich versuche zu verstehen, wie man einen TVP als Parameter zusammen mit anderen typischen typisierten Parametern hat. Wie geht das?
— Snowy

Ich habe diesen Teil noch nicht implementiert.
— Darek

5

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.


2
Korrektur, wir unterstützen es irgendwie ... Sie müssen es nur selbst codieren :)
— Sam Saffron
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.