【问题标题】:How to LINQ filter dbset by list of objects如何通过对象列表 LINQ 过滤 dbset
【发布时间】:2022-01-16 19:56:33
【问题描述】:

我正在尝试使用 SomeModel 的 IEnumerable 请求过滤此类伪结构(field1、field2、field3)实体的数据库集,其中 SomeModel 包含对(field1、field2)(相同的字段子集)

我试过了

var ordersList3 = await _dbContext.MyEntities.
AsNoTracking().
Where(a => request.Contains(new SomeModel() { field1 = a.field1, field2 = a.field2})).
ToListAsync();

但它不起作用

您能否建议通过包含字段子集的模型列表过滤数据库集的正确方法?

【问题讨论】:

  • Where(a => request.Any(b => a.field1 == filterField1, a.field2 == filterField2))
  • 它要求我重写语句 System.InvalidOperationException: The LINQ expression 'b => EntityShaperExpression: SomeEntity ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False .field1 == b.field1' 无法翻译。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。见go.microsoft.com/fwlink/?linkid=2101038
  • 类似问题here。这不是微不足道的,因为 EF 无法将对象列表转换为 SQL,例如 new SomeModel() { field1 = a.field1, field2 = a.field2}
  • 我建议使用LINQKit 动态创建代表您的测试或组合的Expression 树。我有扩展方法可以为各种本地代码执行此操作,作为单个测试转换为 SQL。
  • 您使用的是什么 LINQ:LINQ to Objects / SQL / EF 6.x / EF Core 2.0 / 2.1 / 3.x / 5.x / 6.x?什么数据库提供商?

标签: c# entity-framework linq


【解决方案1】:

我不知道这是否对你来说是必要的,但有时你需要直接写下表达式。因为这可能很有趣,所以你开始吧:

public static Expression<Func<PseudoStructure, bool>> GetPredicate<PseudoStructure>(
    IEnumerable<PseudoStructure> request) {
    var parameter = Expression.Parameter(typeof(PseudoStructure), "o");
    var expression = request.Aggregate(
        (Expression)null,
        (acc, next) => MakeBinary(
            acc, 
            CompareInstances(parameter, next),
            ExpressionType.Or));
    return Expression.Lambda<Func<PseudoStructure, bool>>(expression, parameter);
}

此方法生成一个 Expression>,其中包含检查实例相等性的表达式:

private static Expression CompareInstances<PseudoStructure>(
    ParameterExpression parameter,
    PseudoStructure constant) 
        => typeof(PseudoStructure)
        .GetFields()
        .Select(fieldInfo => Expression.Equal(
            Expression.Constant(fieldInfo.GetValue(constant)),
            Expression.Field(parameter, fieldInfo)))
        .Aggregate(
            (Expression)null,
            (expression, binaryExpression) => MakeBinary(expression, binaryExpression, ExpressionType.And)
        );
    }
}

请注意,相等意味着字段值的相等。 MakeBinary 是 Expression.MakeBinary 的简单包装器:

private static Expression MakeBinary(Expression left, Expression right, ExpressionType expressionType)
    => left == null || right == null ?
        left ?? right
        : Expression.MakeBinary(expressionType, left, right);

你可以这样使用:

public struct Foo
{
    public int A;
    public decimal B;
    public decimal C;
} 

var values = new List<Foo> {
    new Foo {A = 1, B = 2, C = 3},
    new Foo {A = 4, B = 5, C = 6},
    new Foo {A = 7, B = 8, C = 9},
    new Foo {A = 10, B = 11, C = 12}
};

var expression =
    GetPredicate(new[] { 
        new Foo {A = 1, B = 2, C = 3}, 
        new Foo {A = 10, B = 11, C = 12}
    });

var result = values.AsQueryable().Where(expression).ToList();

【讨论】:

    猜你喜欢
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    相关资源
    最近更新 更多