简体   繁体   English

如何 LINQ 按对象列表过滤 dbset

[英]How to LINQ filter dbset by list of objects

I'm trying to filter dbset of entities of such pseudo-structure (field1, field2, field3) using request of IEnumerable of SomeModel where SomeModel contains pairs (field1, field2) (the same fields subset)我正在尝试使用 SomeModel 的 IEnumerable 请求过滤此类伪结构(field1,field2,field3)的实体的数据库集,其中 SomeModel 包含对(field1,field2)(相同的字段子集)

I've tried我试过了

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

but it doesn't work但它不起作用

could you please suggest the correct way of filtering a dbset by list of models containing fields subset?您能否建议通过包含字段子集的模型列表过滤数据库集的正确方法?

I do not know if this is nessessary in your case, but sometimes you need to write down the expressions directly.我不知道这是否对你来说是必要的,但有时你需要直接写下表达式。 As this can be sort of fun, here you go:因为这可能很有趣,所以这里是 go:

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

This method generates an Expression<Func<PseudoStructure, bool>> which consists of Expressions checking equality of instances:此方法生成一个 Expression<Func<PseudoStructure, bool>> ,其中包含检查实例相等性的表达式:

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

Please note that equality means equality of the values of the fields.请注意,相等意味着字段值的相等。 MakeBinary is a simple wrapper for Expression.MakeBinary: MakeBinary 是 Expression.MakeBinary 的简单包装器:

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

You can use this like so:您可以像这样使用它:

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

You get the error because entity framework cannot translate into sql query the expression.您收到错误是因为实体框架无法转换为 sql 查询表达式。 This is due to the predicate inside the where clause.这是由于 where 子句中的谓词。 The correct implementation would be:正确的实现是:

var ordersList3 = await _dbContext.MyEntities.
AsNoTracking().
Where(a => request.Any(r => r.field1 == a.field1 && r.field2 == a.field2})).
ToListAsync();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM