有时 Dapper 或 System.Data 不会为某些数据库(SQL Server 2012 和 2019)上的简单选择查询返回正确的结果

Posted

技术标签:

【中文标题】有时 Dapper 或 System.Data 不会为某些数据库(SQL Server 2012 和 2019)上的简单选择查询返回正确的结果【英文标题】:Sometimes Dapper or System.Data not return correct result for simple select query on some databases (SQL Server 2012 and 2019) 【发布时间】:2021-06-02 23:28:19 【问题描述】:

我有一个简单的查询,它在托管的 web api (.net core 3.1) 内运行批处理操作 IIS。问题是对于某些数据库(通常是大小大于 10-20GB 的数据库),当结果应该为真时,查询返回假。该数据库在一个版本中是 SQL Server 2012,在另一个版本中是 2019。但是在这两种奇怪的行为中都会发生。我的 ORM 是最新版本的 Dapper。查询是这样的:

SELECT 
    CASE Column
        WHEN 'S' THEN 1
        ELSE 0
    END AS Result
FROM 
    Table
WHERE 
    Id = @Id

该列的类型为 CHAR(1)。在 C# 中,我们有以下代码:

bool result= Context.Connection.QueryFirstOrDefault<bool>(
    sql: QUERY,
    param: new  Id = id ,
    transaction: Context.Transaction
);

我已经检查了一些简单的东西,比如连接字符串以及是否存在具有 Id 参数值的寄存器。

在两个数据库中运行 SQL Profiler 我能够捕获 dapper 为数据库发送的查询:

exec sp_executesql N'
SELECT 
    CASE Column
        WHEN ''S'' THEN 1
        ELSE 0
    END AS Result
FROM 
    Table
WHERE 
    Id = @Id',N'@Id int',@Id=103051026

在 SSMS 2019 中运行相同的查询,结果如预期的那样为真,但在生产和开发环境中的应用程序中,某些数据库的结果有时为假。当在单次运行中结果碰巧为假时,批处理内的所有方法调用都会为假(对于此处的批处理,您可以将其理解为在 Web Api 中执行操作以针对 Table 中的数千个寄存器)。

有人可以帮我解决这种奇怪的行为吗?

在@Charliface 的评论之后,我收到了这个异常:

"ERRO" "System.ArgumentNullException: Value cannot be null. (Parameter 'value')
   at Dapper.SqlMapper.ReadChar(Object value) in C:\projects\dapper\Dapper\SqlMapper.cs:line 1878
   at Dapper.SqlMapper.<>c__DisplayClass198_0.<GetStructDeserializer>b__0(IDataReader r) in C:\projects\dapper\Dapper\SqlMapper.cs:line 2914
   at Dapper.SqlMapper.QueryRowImpl[T](IDbConnection cnn, Row row, CommandDefinition& command, Type effectiveType) in C:\projects\dapper\Dapper\SqlMapper.cs:line 1199
   at Dapper.SqlMapper.QueryFirstOrDefault[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Nullable`1 commandTimeout, Nullable`1 commandType) in C:\projects\dapper\Dapper\SqlMapper.cs:line 763
   at ProjectNamespace.Repository.RunSimpleQuerz(Nullable`1 codigoTraco, Int32 implantacaoId) in C:\agents\1\_work\113\s\src\Repositorios\Siac\Repository.cs:line 26
   at ProjectNamespace.Service.Business.Method5(Evento evento, Rule regraValida, DateTime dataExecucao) in C:\agents\1\_work\113\s\src\Servicos\Something\Servico\Business.cs:line 278
   at ProjectNamespace.Service.Business.Method4(Evento evento, Rule regraValida, Dto dto, RegraInteligenciaTecnologica regraCorrente, Nullable`1 codigoTracoCorrente, Int32 anoCorrente, Int32 semanaCorrente, Int32 quatidadeSemanasPeriodo, List`1 list, DateTime dataExecucao) in C:\agents\1\_work\113\s\src\Servicos\Something\Servico\Business.cs:line 100
   at ProjectNamespace.Service.Business.Method3(List`1 listaEventos, DateTime dataExecucao) in C:\agents\1\_work\113\s\src\Servicos\Something\Servico\Business.cs:line 64
   at ProjectNamespace.Service.Business.Method2(Int32 implantacaoId, DateTime dataInicio, DateTime dataExecucao) in C:\agents\1\_work\113\s\src\Servicos\Something\Servico\Business.cs:line 35
   at ProjectNamespace.Service.Business.Method1(Int32 implantacaoId, DateTime dataInicioOperacao, DateTime dataMemoria, Nullable`1 Avaliacao) in C:\agents\1\_work\113\s\src\Servicos\Something\Servico\GerenciadorServico.cs:line 259" "MOTOR" 26

【问题讨论】:

尝试增加sql查询超时?默认为 30 秒 你确定在这种情况下你真的收到了一行吗? 现在我正在运行带有一些日志的应用程序,并期待 querysinglefirstordefault 的动态类型,以检查我是否收到一行。我会尽快在这里提供反馈 SQL 查询超时之前增加了,但我们得到了相同的结果。谢谢你的回答 【参考方案1】:

ADO.NET 和 Dapper 都只是按照提供的方式执行查询;他们无法决定会发生什么,所以:我可以在这里看到两种可能性:1) 查询是正确的,并且对于 某个时间间隔,结果不是您所期望的是,但是因为 数据 不是您所期望的,或者 2)您正在从多个线程访问 Context.Connection(对于同一连接),这可能导致未定义的行为,包括获取并发操作导致查询结果混乱

【讨论】:

就是这样。我的工作类统一的实现和业务层使用它的方式存在一些错误。谢谢你的回答!

以上是关于有时 Dapper 或 System.Data 不会为某些数据库(SQL Server 2012 和 2019)上的简单选择查询返回正确的结果的主要内容,如果未能解决你的问题,请参考以下文章

[转][Dapper]SQL 经验集

sqlsugar 支不支持linq

Dapper: How to get return value ( output value) by call stored procedure

命名空间“System.Data”中不存在类型或命名空间名称“Objects”

未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。试图加载格式不正确的程序。

Dapper vs ADO.Net用反射哪个更快?