Dapper (1.13 Noobget-Paket) erstellt unterschiedliche SQL-Anweisungen, je nachdem, ob es mit einer einfachen ADO.NET-Datenbankverbindung oder mit einer dekorierten Mini-Profiler-Datenbankverbindung verwendet wird.
Beispielcode (getestet mit Postgresql)
Using:
using System.Linq;
using Dapper;
using Npgsql;
using NUnit.Framework;
using StackExchange.Profiling;
using StackExchange.Profiling.Data;
Test1 verwendet eine einfache ADO.NET-Verbindung und schlägt fehl :
[TestFixture]
public class DapperTests {
private const string cnnstr = "HOST=...;DATABASE=...;USER ID=...;PASSWORD=...;";
[Test]
public void Test1() {
using (var cnn = new NpgsqlConnection(cnnstr)) {
cnn.Open();
// The following line fails:
cnn.Query<int>("SELECT 1 WHERE 42 IN @Items", new {Items = new[] {41, 42, 43}}).Single();
// Npgsql.NpgsqlException : ERROR: 42883: operator does not exist: integer = integer[]
}
}
Test2 verwendet eine Mini-Profiler-Verbindung, die um die ADO.NET-Verbindung gewickelt wird und erfolgreich ist :
[Test]
public void Test2() {
using (var cnn = new NpgsqlConnection(cnnstr))
using (var profiled = new ProfiledDbConnection(cnn, MiniProfiler.Start())) {
profiled.Open();
int result = profiled.Query<int>("SELECT 1 WHERE 42 IN @Items", new {Items = new[] {41, 42, 43}}).Single();
Assert.AreEqual(1, result);
}
}
}
Mit Blick auf das generierte SQL wird klar, warum Test1 fehlschlägt:
Arrays unterstützen kein IN.
Warum generiert Dapper verschiedene SQL, wenn es mit / ohne eine profilierte Verbindung verwendet wird?
Warum generiert es ein Array [...] mit einer einfachen Verbindung? Aufgrund der Dokumente von dapper sollte es ein Tupel generieren:
Es gibt eine Klasse "FeatureSupport" in Dapper, die Einstellungen für die spezielle Behandlung von Arrays enthält. Postgresql-Verbindungen sind zur Unterstützung von Arrays markiert, während andere Verbindungstypen ( einschließlich MiniProfiler ProfiledDbConnections ) nicht unterstützt werden.
Wenn die Verbindung keine Arrays unterstützt, erstellt Dapper manuell einen Parameter für jedes Element im Array (wie in der Dokumentation erklärt) - es wird zu einem Tupel in SQL, wie: SELECT 1 WHERE 42 IN (41,42,43)
Wenn die Verbindung Arrays unterstützt (wie Postgres NpgsqlConnection), werden Array-Parameter direkt an die Verbindung übergeben, was zu etwas Hässlichem wie folgt führt : SELECT 1 WHERE 42 IN ( '{41,42,43}' :: int4 [] ) - was schlägt tatsächlich fehl, weil IN Arrays nicht unterstützt.
Relevanter Code ist in der SqlMapper.PackListParameters-Methode.
Daher verursacht das Wechseln zwischen ProfileDbConnections und NpgsqlConnections Probleme, da das generierte SQL anders ist.
Um die Array-Syntax in Postgres-Verbindungen loszuwerden, kann der folgende Code verwendet werden (obwohl er nur auf globaler Ebene funktioniert ...):
using Dapper;
using Npgsql;
using (var cnn = new NpgsqlConnection())
FeatureSupport.Get(cnn).Arrays = false;
Es scheint keine Möglichkeit zu geben, die Array-Syntax auf einer pro-Abfrage- oder pro-Parameter-Ebene zu aktivieren / deaktivieren.
PS .: Ich habe unter https://code.google.com/p/dapper-dot-net/issues/detail?id=107&q=postgres ein Problem für dieses Problem gefunden