自由人雇用:
then
我们的目标是从ASP.NET MVC5项目中定位.net4.7.1。我们的存储库建立在EF .edmx(db-first方法)之上。我们的查询如下:
Devart.Data.dll => 5.0.1878.0
Devart.Data.MySql.dll => 8.10.1086.0
Devart.Data.MySql.Design.dll => 8.10.1086.0
Devart.Data.MySql.Entity.EF6.dll => 8.10.1086.0
EntityFramework => 6.2.0
NFS_SUBFILTER_YN在我们的.edmx中声明为布尔值:
var results = _db.NB_FILTERS
.Select(x => new ReportFiltersDTO { IsHiddenSubFilter = x.NFS_SUBFILTER_YN ?? false })
.ToList();
NB_FILTERS ddl是这样的:
<Property Name="NFS_SUBFILTER_YN" Type="boolean" />
在这种情况下,如果某些行为null,则给定的linq表达式将为所有行返回“true”而不是“false”。罪魁祸首似乎是在自动生成的sql:
CREATE TABLE NB_FILTERS (
[...]
NFS_SUBFILTER_YN BIT(1) NULL,
[...]
)
在Devart推出实际修复程序之前,如何在不更改基础表和/或linq语句本身的情况下解决此错误?
图片的标题说明:
对于那些感兴趣的人,我们已经向devart开发者通知了这个问题,希望能在某个时候解决这个问题:
有趣的是,当涉及的列是可以为空的十进制(x,y)列时,这些查询会起作用[自动生成的sql正确使用CAST(... AS SIGNED)]。似乎在某些类型列表中省略了bit(x),这些类型有资格进行此类处理。
答案 0 :(得分:0)
作为一种临时的止损解决方案,我们选择在mysql上使用EF6拦截器来检测和纠正针对布尔列的动态sql语句(幸运的是,如果不是所有的布尔列都具有_YN后缀)这有很大帮助):
using System.Data;
using System.Data.Common;
using System.Data.Entity.Infrastructure.Interception;
using System.Text.RegularExpressions;
namespace Some.Namespace
{
//to future maintainers the devart mysql drivers for ef6 ver8.10.1086.0 suffer from what appears to be a very annoying b.ug which cause nullable bit(1) columns set to null
//to future maintainers to always be materialized to true when we evaluate them like so
//to future maintainers
//to future maintainers x.SOME_BOOLEAN_COLUMN ?? false
//to future maintainers
//to future maintainers this is obviously flat out wrong and to remedy this issue we intercept the offending sql snippets and hotfix them like so
//to future maintainers
//to future maintainers before => CASE WHEN Extent1.NFS_SUBFILTER_YN IS NULL THEN 1 ELSE Extent1.NFS_SUBFILTER_YN END
//to future maintainers after => CASE WHEN Extent1.NFS_SUBFILTER_YN IS NULL THEN 1 ELSE CAST(Extent1.NFS_SUBFILTER_YN AS SIGNED) END
//to future maintainers
public sealed class MySqlHotFixerCommandInterceptor : IDbCommandInterceptor
{
//beforeexecution
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) => LogWarningBeforeExecutionIfSynchronousExecutionIsFound(command, interceptionContext);
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) => LogWarningBeforeExecutionIfSynchronousExecutionIsFound(command, interceptionContext);
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) => LogWarningBeforeExecutionIfSynchronousExecutionIsFound(command, interceptionContext);
//afterexecution
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {}
static private void LogWarningBeforeExecutionIfSynchronousExecutionIsFound<TResult>(IDbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
if (interceptionContext.Exception != null)
return;
command.CommandText = FaultySwitchCaseSpotter1.Replace(command.CommandText, "CAST($3 AS SIGNED)");
command.CommandText = FaultySwitchCaseSpotter2.Replace(command.CommandText, "CAST($3 AS SIGNED)");
}
private static readonly Regex FaultySwitchCaseSpotter1 = new Regex(@"(?<=CASE\s+WHEN\s+(`?[a-zA-Z0-9_]+?`?[.])?`?[a-zA-Z0-9_]+?`?\s+IS\s+NULL\s+THEN\s+(0|1)\s+ELSE\s+)((`?[a-zA-Z0-9_]+?`?[.])?`?[a-zA-Z0-9_]+?`?)(?=\s*END)", RegexOptions.IgnoreCase);
private static readonly Regex FaultySwitchCaseSpotter2 = new Regex(@"(?<=CASE\s+WHEN\s+(`?[a-zA-Z0-9_]+?`?[.])?`?[a-zA-Z0-9_]+?_YN`?\s+IS\s+NULL\s+THEN\s+(\d+|.[a-zA-Z0-9_]+?|`?[a-zA-Z0-9_]+?`?[.]`?[a-zA-Z0-9_]+?`?)\s+ELSE\s+)((`?[a-zA-Z0-9_]+?`?[.])?`?[a-zA-Z0-9_]+?_YN`?)(?=\s*END)", RegexOptions.IgnoreCase);
}
}
web.config / app.config也需要调整,如下所示:
<configuration>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
[...]
</defaultConnectionFactory>
<providers>
[...]
</providers>
<interceptors>
<!-- keep first -->
<interceptor type="Some.Namespace.MySqlHotFixerCommandInterceptor, Organotiki.Infrastructure.Core">
</interceptor>
[...]
</interceptors>
</entityFramework>
</configuration>