Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# SQL差异EF 6与EF核心_C#_Sql_Sql Server_Entity Framework_Entity Framework Core - Fatal编程技术网

C# SQL差异EF 6与EF核心

C# SQL差异EF 6与EF核心,c#,sql,sql-server,entity-framework,entity-framework-core,C#,Sql,Sql Server,Entity Framework,Entity Framework Core,我正在将一个软件从EF 6迁移到EF Core。在测试期间,我注意到Linq的解释方式有所不同 我的林克 app.Deputies .Include(d => d.User) .Where(d => d.User == null) .ToList() 在EF 6中,它会导致这样一个查询(为了阅读目的而简化) SELECT d.* FROM Deputy d LEFT JOIN User u ON u.Id = d.UserId WHERE u.Id IS NU

我正在将一个软件从EF 6迁移到EF Core。在测试期间,我注意到Linq的解释方式有所不同

我的林克

app.Deputies
   .Include(d => d.User)
   .Where(d => d.User == null)
   .ToList()
在EF 6中,它会导致这样一个查询(为了阅读目的而简化)

SELECT
  d.*
FROM Deputy d
LEFT JOIN User u ON u.Id = d.UserId
WHERE u.Id IS NULL
SELECT
  d.*
FROM Deputy d
LEFT JOIN User u ON u.Id = d.UserId
WHERE d.UserId IS NULL
在efcore中,SQL如下所示

SELECT
  d.*
FROM Deputy d
LEFT JOIN User u ON u.Id = d.UserId
WHERE u.Id IS NULL
SELECT
  d.*
FROM Deputy d
LEFT JOIN User u ON u.Id = d.UserId
WHERE d.UserId IS NULL
即使我执行了
,其中(d=>d.User.Id==null)
也不会更改生成的查询

EF 6的配置如下所示:

.HasOptional(d => d.User).WithMany().HasForeignKey(d => d.UserId);
.HasOne(d => d.User).WithMany().HasForeignKey(d => d.UserId);
EF Core的配置如下所示:

.HasOptional(d => d.User).WithMany().HasForeignKey(d => d.UserId);
.HasOne(d => d.User).WithMany().HasForeignKey(d => d.UserId);
我是否在配置中遗漏了一些东西,或者有没有想到如何实现EF6中相同的SQL

(我正在使用SQL Server)

编辑:DB上代理和用户之间没有FK。(仅在模型中)

这两个查询

SELECT
  d.*
FROM Deputy d
LEFT JOIN User u ON u.Id = d.UserId
WHERE u.Id IS NULL

如果代理在UserId上有外键,则在语义上是相同的

查询之间的唯一区别是代理具有非空UserId,但该UserId在用户表中不存在。如果代理上有外键,就不会发生这种情况

所以EF在这两种情况下的代码生成都是正确的。EF Core的查询更好,因为可以在加入之前对过滤器进行评估

(将我的评论转化为答案)

这是一个有趣的例子,说明了实现中看似无辜的更改可能会产生意想不到的副作用

EF6过滤连接右侧的连接:

SELECT d.*
FROM Deputy d LEFT OUTER JOIN User u 
ON          d.UserId =             u.Id
WHERE                              u.Id IS NULL
左侧的EF核心过滤器:

SELECT d.*
FROM Deputy d LEFT OUTER JOIN User u 
ON          d.UserId =             u.Id
WHERE       d.UserId IS NULL
SQL查询优化器并不疯狂,它指出第二个查询可以简化为:

SELECT d.*
FROM Deputy
WHERE d.UserId IS NULL
查询2和查询3的查询计划是相同的:只有一个索引扫描,而查询1包含一个嵌套循环来组合代理和用户结果

因此,在正常情况下,
User.Id
subsive.UserId
之间存在外键约束,EF核心实现优于前者。但在你的情况下,没有FK。因此
Deputee
s可能具有与任何
User
不匹配的
UserId
s,并且它们被第二个查询过滤掉,而不是第一个查询,而LINQ查询是相同的

这种差异可能非常显著,因此通常我们应该从EF core中改进的查询生成中获益(假设这是经过深思熟虑的)。然而,我们不得不面对,EF6版本是LINQ查询在语义上表达的更好的翻译

您可以通过显式编码外部联接来解决此问题:

from d in db.Deputees
join u in db.Users on d.UserId equals u.Id into ug
from u in ug.DefaultIfEmpty() // LINQ eqivalent of outer join
where u == null
select d
…通过
u.Id
或使用
Any
进行过滤:

db.Deputees.Where(d => !db.Users.Any(u => u.Id == d.UserId))

…翻译成一个
不存在

您发布的两个SQL查询是相同的。只是想知道,为什么您要包括检查null而不是直接检查外键?i、 e
app.depress.Where(d=>d.UserId==null).ToList()
核心版本更好,因为它不需要查询计划中的连接,所以为什么您想要EF6版本?我假设您有。重要的区别在于核心查询在
subsive
上过滤,而不是在
User
上过滤。这使得查询计划更加高效。好吧,我错过了那个。在这种情况下,EF商店模型和实际商店模型之间存在语义差异,您有责任解决它,例如,将其更改为
Any
查询(其中不是
Users.Any(u.Id==d.UserId)
),谢谢您的回答。我知道,如果UserId上有一个FK,它的行为将是相同的。但是DB上没有,只有模型上没有。我是否可以指示modelBuilder,仅在模型中的DB上不存在此关系?或者类似的东西?:)