EF Core - 导致 CS1941 的多个连接条件

Posted

技术标签:

【中文标题】EF Core - 导致 CS1941 的多个连接条件【英文标题】:EF Core - multiple join conditions causing CS1941 【发布时间】:2021-12-21 17:29:18 【问题描述】:

上下文

Itzik Ben-Gan 的T-SQL Fundamentals Third Edition一书在第 3 章中包含以下查询:

SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON O.custid = C.custid
    AND O.orderdate = '20160212';

注意join子句有两个条件:

O.custid = C.custid
AND 
O.orderdate = '20160212'

其他帖子中展示的技术

以下帖子(以及其他帖子)演示了如何通过JOIN 使用多个条件

LINQ to Entity : Multiple join conditions

LINQ Join with Multiple Conditions in On Clause

问题

根据上面分享的帖子,这是我想出的 EF Core 版本的查询:

var result =
    from customer in db.Customers
    join order in db.Orders
    on
    new
    
        Key1 = customer.Custid,
        Key2 = true
    
    equals 
    new
    
        Key1 = order.Custid,
        Key2 = order.Orderdate == new DateTime(2016, 2, 12)
                        
    into Abc
    from abc in Abc.DefaultIfEmpty()
    select new
    
        customer.Custid,
        customer.Companyname,
        Orderid = abc == null ? -1 : abc.Orderid,
        Orderdate = abc == null ? new DateTime() : abc.Orderdate
    ;

但是,使用该代码时,join 上会出现一条红色波浪线,并显示以下消息:

CS1941:join 子句中的表达式之一的类型不正确。调用“GroupJoin”时类型推断失败。

docs.microsoft.com 上的编译器错误链接:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs1941?f1url=%3FappId%3Droslyn%26k%3Dk(CS1941)

问题

我根据其他帖子中显示的示例对我的版本进行了建模。所以不确定我的例子中是什么导致了这个问题。

为给定的 SQL 调用设置 LINQ 查询的好方法是什么?

谢谢!

注意事项

如果您真的想自己运行查询,上述查询位于此处提供的项目中:

https://github.com/dharmatech/TSqlEf/blob/master/Chapter3e7/Program.cs

有关如何设置数据库,请参阅项目自述文件:

https://github.com/dharmatech/TSqlEf

克莱的建议

这是一种基于 Cly 的回答的方法,它使用 where 子句:

var result =
    from customer in db.Customers
    join order in db.Orders
    on customer.Custid equals order.Custid
    into Abc
    from abc in Abc.DefaultIfEmpty()
    where abc.Orderdate == new DateTime(2016, 2, 12)
    select new
    
        customer.Custid,
        customer.Companyname,
        Orderid = abc == null ? -1 : abc.Orderid,
        Orderdate = abc == null ? new DateTime() : abc.Orderdate
    ;

如果我使用以下输出结果:

foreach (var item in result)

    Console.WriteLine("0 1 2", item.Custid, item.Companyname, item.Orderid, item.Orderdate);


Console.WriteLine();
Console.WriteLine("0 rows", result.Count());

我得到以下信息:

48 Customer DVFMB 10883
45 Customer QXPPT 10884
76 Customer SFOGW 10885

3 rows

如果我在 SSMS 中运行原始 SQL 代码,我会得到 91 行。

书中的练习描述还指出,预计需要 91 行。这是练习文本和预期输出:

这里是解决方案文本,它涉及连接背后的微妙之处以及为什么where 在这种情况下不适用:

【问题讨论】:

我会尝试从加入中删除Key2 部分并将order.Orderdate == new DateTime(2016, 2, 12) 添加为where。它根本不是连接表达式,而是连接实体一侧的过滤器。 @cly,感谢您的建议!你会说应该在哪里插入where 子句?我试图将它放在各个地方的查询中,它们都会导致错误。 试试from abc in Abc.Where(abc => abc.Orderdate == new DateTime(2016, 2, 12)).DefaultIfEmpty() @Charlieface,Omgosh ......这似乎完美无缺!我添加了一个答案来说明您建议的方法:***.com/a/69892036/268581 非常有趣...谢谢! @Charlieface,如果您决定根据您的建议添加自己的答案,我会投票赞成并删除我的。 :-) 【参考方案1】:

Key2 not-so-join-but-a-side-filter 部分取出到where 看起来像这样:

var result =
from customer in db.Customers
join order in db.Orders
on customer.Custid equals order.Custid into Abc
from abc in Abc.DefaultIfEmpty()
where abc.Orderdate == new DateTime(2016, 2, 12)
select new

    customer.Custid,
    customer.Companyname,
    Orderid = abc == null ? -1 : abc.Orderid,
    Orderdate = abc == null ? new DateTime() : abc.Orderdate
;

【讨论】:

感谢克莱的澄清!所以,我从这个版本(3 行)得到的输出与本书所期望的(91 行)不同。我已经用一个部分更新了这个问题,该部分展示了你的方法,并包含了书中的注释,阐明了为什么 where 会导致不同的结果。 新的细节显示了不同的要求。 “解决方案查询”中有一个您尚未使用的修饰符 :) 在我的版本中找到它的位置并使用适当的语法编写它。通过反复试验学习是一件非常好的事情! :) 嗯...有趣的提示!当您说查询中有一个修饰符不在您的版本中时,您指的是AND吗? Charlieface 的建议似乎奏效了。我已经在此基础上添加了答案。那里的方法是否与您的想法相似?【参考方案2】:

只需使用过滤的包括:https://docs.microsoft.com/en-us/ef/core/querying/related-data/eager#filtered-include

【讨论】:

【参考方案3】:

查理脸的建议

这是一种基于 Charlieface 在上述评论中的建议的方法。它确实似乎有效!

var result =
    from customer in db.Customers
    join order in db.Orders
    on customer.Custid equals order.Custid
    into Abc
    from abc in Abc.Where(abc => abc.Orderdate == new DateTime(2016, 2, 12)).DefaultIfEmpty()
    select new
    
        customer.Custid,
        customer.Companyname,
        Orderid = abc == null ? -1 : abc.Orderid,
        Orderdate = abc == null ? new DateTime() : abc.Orderdate
    ;

使用以下输出结果:

foreach (var item in result)

    Console.WriteLine("0,3 1 2,6 3,10", 
        item.Custid, 
        item.Companyname, 
        item.Orderid == -1 ? "NULL" : item.Orderid, 
        item.Orderid == -1 ? "NULL" : item.Orderdate.ToString("yyyy-MM-dd"));

显示以下内容:

 72 Customer AHPOP   NULL       NULL
 58 Customer AHXHT   NULL       NULL
 25 Customer AZJED   NULL       NULL
 18 Customer BSVAR   NULL       NULL
 91 Customer CCFIZ   NULL       NULL
 68 Customer CCKOT   NULL       NULL
 49 Customer CQRAA   NULL       NULL
 24 Customer CYZTN   NULL       NULL
 22 Customer DTDMN   NULL       NULL
 48 Customer DVFMB  10883 2016-02-12
 10 Customer EEALV   NULL       NULL
 40 Customer EFFTC   NULL       NULL
 85 Customer ENQZT   NULL       NULL
 82 Customer EYHKM   NULL       NULL
 79 Customer FAPSM   NULL       NULL
 17 Customer FEVNN   NULL       NULL
 37 Customer FRXZL   NULL       NULL
 33 Customer FVXPQ   NULL       NULL
 53 Customer GCJSG   NULL       NULL
 39 Customer GLLAG   NULL       NULL
 16 Customer GYBBY   NULL       NULL
  4 Customer HFBZG   NULL       NULL
  5 Customer HGVLZ   NULL       NULL
 42 Customer IAIJK   NULL       NULL
 34 Customer IBVRG   NULL       NULL
 63 Customer IRRVL   NULL       NULL
 73 Customer JMIKW   NULL       NULL
 15 Customer JUWXK   NULL       NULL
 50 Customer JYPSC   NULL       NULL
  3 Customer KBUDE   NULL       NULL
 21 Customer KIDPX   NULL       NULL
 30 Customer KSLQF   NULL       NULL
 55 Customer KZQZT   NULL       NULL
 71 Customer LCOUJ   NULL       NULL
 77 Customer LCYBZ   NULL       NULL
 66 Customer LHANT   NULL       NULL
 38 Customer LJUCA   NULL       NULL
 59 Customer LOLJO   NULL       NULL
 36 Customer LVJSO   NULL       NULL
 64 Customer LWGMD   NULL       NULL
 29 Customer MDLWA   NULL       NULL
  2 Customer MLTDN   NULL       NULL
 78 Customer NLTYP   NULL       NULL
 84 Customer NRCSK   NULL       NULL
  1 Customer NRZBB   NULL       NULL
 65 Customer NYUHS   NULL       NULL
 44 Customer OXFRU   NULL       NULL
 12 Customer PSNMQ   NULL       NULL
 47 Customer PSQUZ   NULL       NULL
 51 Customer PVDZC   NULL       NULL
 52 Customer PZNLA   NULL       NULL
 56 Customer QNIVZ   NULL       NULL
  8 Customer QUHWH   NULL       NULL
 67 Customer QVEPD   NULL       NULL
 45 Customer QXPPT  10884 2016-02-12
  7 Customer QXVLA   NULL       NULL
 60 Customer QZURI   NULL       NULL
 19 Customer RFNQC   NULL       NULL
  9 Customer RTXGC   NULL       NULL
 76 Customer SFOGW  10885 2016-02-12
 69 Customer SIUIH   NULL       NULL
 86 Customer SNXOJ   NULL       NULL
 88 Customer SRQVM   NULL       NULL
 54 Customer TDKEG   NULL       NULL
 20 Customer THHDP   NULL       NULL
 70 Customer TMXGN   NULL       NULL
 11 Customer UBHAU   NULL       NULL
 43 Customer UISOJ   NULL       NULL
 35 Customer UMTLM   NULL       NULL
 26 Customer USDBG   NULL       NULL
 13 Customer VMLOG   NULL       NULL
 80 Customer VONTK   NULL       NULL
 62 Customer WFIZJ   NULL       NULL
 27 Customer WMFEA   NULL       NULL
 14 Customer WNMAF   NULL       NULL
 61 Customer WULWD   NULL       NULL
 57 Customer WVAXS   NULL       NULL
 23 Customer WVFAF   NULL       NULL
 90 Customer XBBVR   NULL       NULL
  6 Customer XHXJV   NULL       NULL
 41 Customer XIIWM   NULL       NULL
 75 Customer XOJYP   NULL       NULL
 46 Customer XPNIK   NULL       NULL
 28 Customer XYUFB   NULL       NULL
 89 Customer YBQTI   NULL       NULL
 31 Customer YJCBX   NULL       NULL
 81 Customer YQQWW   NULL       NULL
 74 Customer YSHXL   NULL       NULL
 32 Customer YSIQX   NULL       NULL
 87 Customer ZHYOS   NULL       NULL
 83 Customer ZRNDE   NULL       NULL

91 rows

【讨论】:

以上是关于EF Core - 导致 CS1941 的多个连接条件的主要内容,如果未能解决你的问题,请参考以下文章

EF Core 调用具有多个连接的存储过程并映射相关数据

使用托管标识与 Azure SQL 的 EF Core 连接

EF Core 多个 HTTP 请求引发错误

EF CORE - 创建一对多地图

在遍历 EF Core 5 中的多个条件包含后查询任何条目

有没有办法将已经打开的 MySQL 连接传递给 EF Core DbContext ?用于多线程目的