在EF Core 2中使用Contains作为(NOT)EXIST在EF Core 3.1中不再有效



从EF Core 2.2升级到EF Core 3.1后;不再在客户端上评估LINQ查询";问题
我在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();

在EF Core 3.1中,第二个查询在Contains方法上失败;不能翻译";错误经过一番尝试和错误,我将其改写如下:

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));

现在,尽管这是可行的,但这不是我想要的,因为我希望整个查询在服务器上执行。这可能吗?

我可以在第二个查询中获得第一个查询(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

尝试使用集合为"的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();

此外,我非常确信EF Core 2以前在内存中执行过这种过滤——请参阅自动静默客户端评估的突破性变化:

旧行为

在3.0之前,当EF Core无法将查询中的表达式转换为SQL或参数时,它会自动在客户端上评估该表达式。默认情况下,客户端对可能代价高昂的表达式的评估只会触发警告。

新行为

从3.0开始,EF Core只允许在客户端上评估顶级投影(查询中的最后一个Select((调用(中的表达式。当查询的任何其他部分中的表达式都无法转换为SQL或参数时,将引发异常。

最新更新