[英]Using Contains as (NOT) EXIST in EF Core 2 no longer works in EF Core 3.1
After upgrading from EF Core 2.2 to EF Core 3.1 I run into the "LINQ queries are no longer evaluated on the client" issue.从 EF Core 2.2 升级到 EF Core 3.1 后,我遇到了“不再在客户端上评估 LINQ 查询”问题。
I have the below queries in 2.2 which work fine:我在 2.2 中有以下查询,它们工作正常:
var entQry = await
(from up in _dbContext.Profiles
join pa in _dbContext.Access
on up.ProfileId equals pa.ProfileId
where (up.IdentityUserId == identityUser.Id)
select new
{
pa.LibraryId
}).ToListAsync();
var libQry = await
(from en in _dbContext.Entities
join pa in _dbContext.Access
on en.LibraryId equals pa.ObjectId
where (up.IdentityUserId == identityUser.Id
&& !entQry.Contains(new { en.LibraryId }))
select new
{
Id = en.Id
}).ToListAsync();
In EF Core 3.1 the second query fails on the Contains method with the "cannot translate" error.在 EF Core 3.1 中,第二个查询在 Contains 方法上失败,并出现“无法翻译”错误。 After some trial and error I have rewritten this as follows:
经过反复试验,我将其重写如下:
var libQry2 = await
(from en in _dbContext.Entities
join pa in _dbContext.Access
on en.LibraryId equals pa.ObjectId
where (up.IdentityUserId == identityUser.Id)
select new
{
Id = en.Id
}).ToListAsync();
var libQry = libQry2.Where(w => !entQry.Any(c => c.LibraryId == w.Id));
Now although this works this is not what I want because I want the entire query to be executed on the server.现在虽然这可行,但这不是我想要的,因为我希望在服务器上执行整个查询。 Is that possible?
那可能吗?
Can I get the first query (entQry) as a sub query in the second query so that it translates to SQL as:我可以将第一个查询 (entQry) 作为第二个查询中的子查询,以便它转换为 SQL 为:
SELECT en.Id
FROM Entities en JOIN Access pa ON en.LibraryId equals pa.ObjectId
WHERE x.id NOT IN (SELECT up.LibraryId FROM Profiles up JOIN Access pa ON up.ProfileId = pa.ProfileId)
AND up.IdentityUserId == @identityUser.Id
Try using Contains
with collection of "primitive" types:尝试使用
Contains
“原始”类型的集合:
var entIds = await
(from up in _dbContext.Profiles
join pa in _dbContext.Access
on up.ProfileId equals pa.ProfileId
where (up.IdentityUserId == identityUser.Id)
select pa.LibraryId)
.ToListAsync();
var libQry = await
(from en in _dbContext.Entities
join pa in _dbContext.Access
on en.LibraryId equals pa.ObjectId
where (up.IdentityUserId == identityUser.Id
&& !entIds.Contains(en.LibraryId))
select new
{
Id = en.Id
}).ToListAsync();
Also I'm pretty much sure that EF Core 2 previously executed this filtering in-memory - see the automatic silent client side evaluation breaking change :此外,我非常确定 EF Core 2 之前在内存中执行了此过滤 - 请参阅自动静默客户端评估重大更改:
Old behavior
旧行为
Before 3.0, when EF Core couldn't convert an expression that was part of a query to either SQL or a parameter, it automatically evaluated the expression on the client.
在 3.0 之前,当 EF Core 无法将作为查询一部分的表达式转换为 SQL 或参数时,它会自动在客户端上计算表达式。 By default, client evaluation of potentially expensive expressions only triggered a warning.
默认情况下,客户端对可能昂贵的表达式的评估只会触发警告。
New behavior
新行为
Starting with 3.0, EF Core only allows expressions in the top-level projection (the last Select() call in the query) to be evaluated on the client.
从 3.0 开始,EF Core 仅允许在客户端评估顶级投影(查询中的最后一个 Select() 调用)中的表达式。 When expressions in any other part of the query can't be converted to either SQL or a parameter, an exception is thrown.
当查询的任何其他部分中的表达式无法转换为 SQL 或参数时,将引发异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.