Pourquoi Dapper génère-t-il un code SQL différent avec / sans connexion de mini-profileur

dapper mvcminiprofiler mvc-mini-profiler npgsql

Question

Dapper (1.13 Noobget Package) crée différentes instructions SQL selon qu'il est utilisé avec une connexion de base de données ADO.NET simple ou avec une connexion de base de données de mini-profileur décorée.

Exemple de code (testé avec Postgresql)

Usages:

using System.Linq;
using Dapper;
using Npgsql;
using NUnit.Framework;
using StackExchange.Profiling;
using StackExchange.Profiling.Data;

Test1 utilise une connexion ADO.NET simple et échoue :

[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 utilise une connexion de mini-profileur entourant la connexion ADO.NET et réussit :

  [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);
    }
  }
}

En regardant le code SQL généré, il devient clair que Test1 échoue:

  • SQL de Test1: SELECT 1 WHERE 42 IN ( (array [41,42,43]) :: int4 [] )
  • SQL of Test2: SELECT 1 WHERE 42 IN ((((41)), ((42)), ((43)))

Les tableaux ne prennent pas en charge IN.

Pourquoi dapper génère-t-il un code SQL différent lorsqu'il est utilisé avec / sans connexion profilée?

Pourquoi génère-t-il un tableau avec [...] une connexion simple? En raison des documents de Dapper, il devrait générer un tuple:

Dapper List Support

Réponse populaire

Il existe une classe "FeatureSupport" dans Dapper qui contient des paramètres pour un traitement spécial des tableaux. Les connexions postgresql sont marquées pour prendre en charge les baies, tandis que les autres types de connexion ( qui incluent MiniProfiler ProfiledDbConnections ) sont marqués pour ne pas prendre en charge les baies.

Si la connexion ne prend pas en charge les tableaux, Dapper crée manuellement un paramètre pour chaque élément du tableau (comme expliqué dans les documents) - il devient un tuple dans SQL, comme: SELECT 1 WHERE 42 IN (41,42,43)

Si la connexion prend en charge les tableaux (comme le NpgsqlConnection de Postgres), les paramètres du tableau sont transmis directement à la connexion, donnant lieu à quelque chose de laid comme: SELECT 1 WHERE 42 IN ( '{41,42,43}' :: int4 [] ) échoue en réalité car IN ne supporte pas les tableaux.

Le code pertinent se trouve dans la méthode SqlMapper.PackListParameters.

Par conséquent, basculer entre ProfiledDbConnections et NpgsqlConnections pose des problèmes car le SQL généré sera différent.

Pour se débarrasser de la syntaxe de tableau dans les connexions Postgres, le code suivant peut être utilisé (même s'il ne fonctionne qu'au niveau global ...):

using Dapper;
using Npgsql;

using (var cnn = new NpgsqlConnection())
  FeatureSupport.Get(cnn).Arrays = false;

Il ne semble pas y avoir de moyen pour activer / désactiver la syntaxe du tableau au niveau de chaque requête ou paramètre.

PS.: J'ai trouvé un problème pour ce problème sur https://code.google.com/p/dapper-dot-net/issues/detail?id=107&q=postgres



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi