8

我正在尝试在 EF Core 中构建一个健全的查询,该查询返回一组事物,而这些事物又派生自一组事物。基本上在原始 SQL 中,一个人会做一个 JOIN。

它在 ASP.NET Core 中,因此初始集合是SecurityPrincipal对象上的角色列表:

var roles = User.FindAll(ClaimTypes.Role).Select(r=>r.Value);

然后将这些角色映射到我们数据库中的组,因此我可以查找它们:

var groupsQuery = dbContext.Groups.Where(g=>roles.Any(r=>r==g.GroupName));
var groups = await groupsQuery.ToListAsync();

此查询非常满意,并按预期返回一组组。然而,这些组可以访问另一个资源,这是我真正想要的,因为它是多对多关系,所以有一个桥接表。

这是我试图查询 AssetGroup 加入表,以便我可以获取映射到SecurityPrincipal.

var assetGroupsQuery = dbContext.AssetsGroups.Where(ag => groupsQuery.Any(ag => ag.Id == a.GroupId));
var assetGroups = await assetGroupsQuery.ToListAsync();

当我执行第二个查询时,我的输出窗口中有很多垃圾邮件:

  The LINQ expression 'where ([ag].Id == [ag].GroupId)' could not be translated and will be evaluated locally.
  The LINQ expression 'Any()' could not be translated and will be evaluated locally.
  The LINQ expression 'where {from Group g in __groups_0 where ([ag].Id == [ag].GroupId) select [ag] => Any()}' could not be translated and will be evaluated locally.
  The LINQ expression 'where ([ag].Id == [ag].GroupId)' could not be translated and will be evaluated locally.
  The LINQ expression 'Any()' could not be translated and will be evaluated locally.

关于如何表达这样的嵌套查询以便 EF Core 可以正确组合单个 SQL 查询的任何线索?

4

1 回答 1

16

一般来说,避免在内存集合中使用Any或任何 LINQ 运算符,而不是像你Contains内存集合roles(根据代码应该是 type IEnumerable<string>)。

换句话说,而不是

.Where(g => roles.Any(r => r == g.GroupName))

使用功能等效的

.Where(g => roles.Contains(g.GroupName))

后者保证被翻译成 SQL IN,而前者不是。

有趣且同时具有误导性的是,EF Core 试图变得聪明并以与 相同的方式翻译前者Contains,并在执行包含查询时成功,但在用作另一个查询的一部分时却没有。

它可以被认为是当前的 EF Core 实现缺陷。但是解决方法/解决方案是(如开头所述)不依赖它并始终使用Contains.

于 2019-01-23T09:14:42.097 回答