如何在 .NET Core 3.0 Entity Framework 中执行群组加入?
How to perform a group join in .NET Core 3.0 Entity Framework?
随着 .NET Core 3.0 的变化,我得到了
... NavigationExpandingExpressionVisitor' failed. This may indicate
either a bug or a limitation in EF Core. See
https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed
information.) ---> System.InvalidOperationException: Processing of
the LINQ expression '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 查询(或上面的方法语法),它将 Studies 加入到 Patients 中,并将 Studies 设置为空列表,如果没有针对给定患者的研究,则设置为 null。
有什么想法吗?这在 .NET Core 2.2 中有效。上面的 MSFT link 还提到关键的重大变化与客户端评估有关,并避免生成的查询读取整个表,然后必须在客户端连接或过滤这些表。然而,通过这个简单的查询,加入应该很容易在服务器端完成。
正如所讨论的那样 here,您正在尝试数据库不支持的查询。 EF Core 2 使用客户端评估来让您的代码工作,但 EF Core 3 拒绝了,因为随着数据集的增加,客户端的便利性是以难以调试的性能问题为代价的。
您可以使用 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
为了解决 N+1 problem,上面的示例抓取了完整的 Patient 和 Study 实体,但您可以改用 cherry pick 列。如果您需要的患者数据太大而无法为每个研究重复,则在联合查询中 select 仅患者 ID,在单独的非联合查询中查询其余患者数据。
遇到了完全相同的问题,并且为此苦苦挣扎。事实证明,.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();
随着 .NET Core 3.0 的变化,我得到了
... NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.) ---> System.InvalidOperationException: Processing of the LINQ expression '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 查询(或上面的方法语法),它将 Studies 加入到 Patients 中,并将 Studies 设置为空列表,如果没有针对给定患者的研究,则设置为 null。
有什么想法吗?这在 .NET Core 2.2 中有效。上面的 MSFT link 还提到关键的重大变化与客户端评估有关,并避免生成的查询读取整个表,然后必须在客户端连接或过滤这些表。然而,通过这个简单的查询,加入应该很容易在服务器端完成。
正如所讨论的那样 here,您正在尝试数据库不支持的查询。 EF Core 2 使用客户端评估来让您的代码工作,但 EF Core 3 拒绝了,因为随着数据集的增加,客户端的便利性是以难以调试的性能问题为代价的。
您可以使用 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
为了解决 N+1 problem,上面的示例抓取了完整的 Patient 和 Study 实体,但您可以改用 cherry pick 列。如果您需要的患者数据太大而无法为每个研究重复,则在联合查询中 select 仅患者 ID,在单独的非联合查询中查询其余患者数据。
遇到了完全相同的问题,并且为此苦苦挣扎。事实证明,.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();