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中。因此可以使用基于 Contains
的 Where
运算符代替 Intersect
,然后简单地计算结果(或使用 Count
的谓词版本作为 [=20= 的快捷方式]), 例如替换
x.Locations.Select(y => y.Id).Intersect(locationIdsL).Count() == locationIdsL.Count
和
x.Locations.Count(y => locationIdsL.Contains(y.Id)) == locationIdsL.Count
我目前正在尝试将 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中。因此可以使用基于 Contains
的 Where
运算符代替 Intersect
,然后简单地计算结果(或使用 Count
的谓词版本作为 [=20= 的快捷方式]), 例如替换
x.Locations.Select(y => y.Id).Intersect(locationIdsL).Count() == locationIdsL.Count
和
x.Locations.Count(y => locationIdsL.Contains(y.Id)) == locationIdsL.Count