如何在.NET Core 3.0实体框架中执行组联接?


13

随着对.NET Core 3.0的更改,我得到了

... NavigationExpandingExpressionVisitor'失败。这可能表示EF Core中存在错误或限制。有关更多详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2101433。)---> System.InvalidOperationException:处理LINQ表达式'GroupJoin,...

这是一个非常简单的查询,因此必须有一种在.NET CORE 3.0中执行该查询的方法:

 var queryResults1 = await patients
            .GroupJoin(
                _context.Studies,
                p => p.Id,
                s => s.Patient.Id,
                (p, studies) => new 
                {
                    p.DateOfBirth,
                    p.Id,
                    p.Name,
                    p.Sex,
                   Studies =studies.Select(s1=>s1)
                }
            )
            .AsNoTracking().ToListAsync();

我基本上是在寻找一个Linq查询(或上面的方法语法),它将查询与研究合并到患者中,并将研究设置为空列表,如果给定患者没有研究,则将其设置为null。

有任何想法吗?这在.NET Core 2.2中正常工作。此外,上面的MSFT链接还提到,密钥突破更改与客户端评估有关,并且避免了生成的查询读取整个表,然后必须对这些表进行联接或过滤。但是,通过此简单查询,可以在服务器端轻松进行联接。

Answers:


11

作为讨论在这里,你试图不被支持的数据库的查询。EF Core 2使用客户端评估来使您的代码正常工作,但EF Core 3拒绝了,因为随着数据集的增加,客户端的便利性以难以调试的性能问题为代价。

您可以使用use DefaultIfEmpty退出患者的研究,然后使用手动分组ToLookup

var query =
    from p in db.Patients
    join s in db.Studies on p.Id equals s.PatientId into studies
    from s in studies.DefaultIfEmpty()
    select new { Patient = p, Study = s };

var grouping = query.ToLookup(e => e.Patient); // Grouping done client side

上面的示例获取了完整的Patient和Study实体,但是您可以改为选择列。如果您需要患者的数据太大而无法为每个研究重复,则在合并的查询中仅选择患者ID,然后在单独的非合并查询中查询其余的患者数据。


2
回答有效!我猜在查询翻译器中还有一些工作要做。这样的简单查询应该可以翻译。假设FK /索引正确,则随着2个表的简单组联接不会出现性能问题,因为数据集会增加。我怀疑很多人都会遇到这个问题,一个2表组联接是相当标准且经常使用的查询。
shelbypereira

@ she72我同意。看起来问题出在LINQ和SQL使用“ group”关键字的方式不同。EF Core应该将LINQ groupby转换为左联接,在这种情况下这样做不会拉回比预期更多的行。我张贴了据此评论
爱德华·布雷

我有一个后续问题,我仍在试图理解为什么这种查询类型的分组需要在客户端进行,这似乎是新LINQ框架的局限性。对于上述情况,我看不到任何以意外方式减慢客户端执行速度的风险。你能澄清一下吗?
shelbypereira

1
作为进一步的跟进,主要关注的是:如果您对每个患者进行1000项研究,那么在您重新编写的查询中,哪一组将客户端分组,那么我将从DB中加载每个患者1000次吗?是否有其他方法可以强制在数据库中完成这项工作并返回分组结果?
shelbypereira

1
@ shev72数据库唯一可理解的分组涉及聚合,例如查询患者,每个患者的研究计数。数据库始终返回矩形数据集。客户必须组成一个层次分组。您可以将其视为客户端评估或ORM的一部分。在层次结构分组中,将重复父实体数据,尽管不会重新查询。
爱德华·布雷

0

遇到了完全相同的问题,并为此付出了巨大的努力。事实证明.net Core 3.0不支持方法语法中的Join或Groupjoin(还可以吗?)。有趣的是,它确实可以在查询语法中使用。

试试这个,它是查询语法和一些方法语法。这很好地转换为带有良好左外部联接的正确SQL查询,并在数据库上进行处理。我没有您的模型,所以您需要自行检查语法...。

var queryResults1 = 
    (from p in _context.patients
    from s in _context.Studies.Where(st => st.PatientId == p.Id).DefaultIfEmpty()
    select new
    {
        p.DateOfBirth,
        p.Id,
        p.Name,
        p.Sex,
        Studies = studies.Select(s1 => s1)
    }).ToListAsync();

顺便说一下,使用方法语法的Join和GroupJoin DO可以与非核心Framework和EF一起使用。并转换为已处理的服务器端正确的查询
hwmaat

1
什么是研究中的研究。Select(s1 => s1)
Ankur Arora

该模型未包含在问题中,因此我不知道研究模型。我最好的猜测是这是模型中的虚拟集合。
hwmaat
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.