为什么Dapper使用/不使用mini-profiler连接生成不同的SQL

stm*_*max 6 npgsql dapper mvc-mini-profiler mvcminiprofiler

Dapper(1.13 Noobget Package)创建不同的SQL语句,具体取决于它是与普通的ADO.NET数据库连接一起使用还是与装饰的迷你探查器数据库连接一起使用.

示例代码(使用Postgresql测试)

Usings:

using System.Linq;
using Dapper;
using Npgsql;
using NUnit.Framework;
using StackExchange.Profiling;
using StackExchange.Profiling.Data;
Run Code Online (Sandbox Code Playgroud)

Test1使用普通的ADO.NET连接并失败:

[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[]
    }
  }
Run Code Online (Sandbox Code Playgroud)

Test2使用围绕ADO.NET连接的mini-profiler连接并成功:

  [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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

查看生成的SQL,可以清楚地了解Test1失败的原因:

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

数组不支持IN.

为什么dapper在使用/不使用配置文件连接时生成不同的SQL?

为什么它生成一个带有普通连接的数组?由于dapper的文档,它应该生成一个元组:

Dapper List支持

stm*_*max 9

Dapper中有一个"FeatureSupport"类,其中包含对数组进行特殊处理的设置.Postgresql连接被标记为支持数组,而其他连接类型(包括MiniProfiler ProfiledDbConnections)被标记为不支持数组.

如果连接不支持数组,Dapper会手动为数组中的每个项创建一个参数(如文档中所述) - 它将成为SQL中的元组,如:SELECT 1 WHERE 42 IN (41,42,43)

如果连接支持数组(如Postgres的NpgsqlConnection),则数组参数会直接传递给连接,从而产生一些难看的东西:SELECT 1 WHERE 42 IN('{41,42,43}':: int4 []) - 其中实际上失败了,因为IN不支持数组.

相关代码位于SqlMapper.PackListParameters方法中.

因此,在ProfiledDbConnections和NpgsqlConnections之间切换会导致问题,因为生成的SQL会有所不同.

要消除Postgres连接中的数组语法,可以使用以下代码(尽管它仅适用于全局级别...):

using Dapper;
using Npgsql;

using (var cnn = new NpgsqlConnection())
  FeatureSupport.Get(cnn).Arrays = false;
Run Code Online (Sandbox Code Playgroud)

似乎没有办法在每个查询或每个参数级别上启用/禁用数组语法.

PS.:我在https://code.google.com/p/dapper-dot-net/issues/detail?id=107&q=postgres上发现了此问题的问题

  • 今天我学到了; 谢谢; 哇我需要清除拉动请求和问题! (3认同)