EF Core 在列表和 child 元素 returns "ArgumentNullException" 的 属性 之间相交

EF Core Intersect between List and Property of child element returns "ArgumentNullException"

我目前正在尝试将 ID 列表与我的数据库实体的 child 属性 相交。

这样做的目的是找到所有列表 ID 与 child 实体“位置”中的至少一个实体相匹配的所有“表单”记录。 我相信 SQL 等价物会在加入的 table “位置”上执行 IN。

相关元素的结构是这样的:(我有意省略了所有其他属性)。

public class Form
{

    [Column("FormId"), DatabaseGenerated(DatabaseGeneratedOption.Identity), Key]
    public Guid Id { get; set; }
    public virtual ICollection<Location> Locations { get; set; }
}

public class Location
{
    [Column("LocationId"), DatabaseGenerated(DatabaseGeneratedOption.Identity), Key]
    public Guid Id { get; set; }
}

我正在尝试执行以下操作:

var locationIdsL = locationIds.Split(',').Select(Guid.Parse).ToList();

return baseQuery.Include(x => x.Locations).Where(x => x.Locations.Select(y => y.Id).Intersect(locationIdsL).Count() == locationIdsL.Count);

* 假设 locationIdsL 变量是一个有效的 Guid 列表。

上面的代码returns以下异常:

System.ArgumentNullException: Value cannot be null. (Parameter 'parameter') at System.Linq.Expressions.Expression.Lambda(Expression body, String name, Boolean tailCall, IEnumerable`1 parameters) at System.Linq.Expressions.Expression.Lambda(Expression body, ParameterExpression[] parameters) at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.ReducingExpressionVisitor.Visit(Expression expression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)

但是,如果我像这样手动使用 collection:

List<Form> forms = new List<Form>();
foreach (var form in baseQuery.Include(x => x.Locations))
{
    var locations = form.Locations;
    if (locations.Select(x => x.Id).Intersect(locationIdsL).Count() == locationIdsL.Count)
    {
        forms.Add(form);
    }
}

forms collection 得到了我期望看到的项目,最值得注意的是,无一例外。

由于显而易见的原因,后者不是可接受的table解决方案,因为它需要加载整个数据集。

我不确定我在这里遗漏了什么,因为 EFCore 应该能够翻译第一个查询。

老实说,我的方法可能完全错误,我可能完全是“anti-patterning”我的查询,我不确定;欢迎提出任何建议。

I am not sure what I am missing here as EFCore should be able to translate the first query

如果 locationIdsL 变量持有数据库查询(非内存中 IQueryable<T> 类型),可能会。问题在于它包含内存中的集合,到目前为止,LINQ to Entities 查询中唯一支持的内存中集合操作是“原始”值集合上的 Contains,它直接转换为 SQL IN (val1, val2, ..., valN)构造。

幸运的是,这足以实现所讨论的查询。因为setA和setB的交集无非就是setA中的元素contained在一个setB中。因此可以使用基于 ContainsWhere 运算符代替 Intersect,然后简单地计算结果(或使用 Count 的谓词版本作为 [=20= 的快捷方式]), 例如替换

x.Locations.Select(y => y.Id).Intersect(locationIdsL).Count() == locationIdsL.Count

x.Locations.Count(y => locationIdsL.Contains(y.Id)) == locationIdsL.Count