基于内存中原语组合的查询的实体框架解决方案

本文关键字:组合 查询 实体 解决方案 框架 原语 于内存 内存 | 更新日期: 2023-09-27 18:16:25

我有一个类T:

class T {
   int Prop1Id;
   int Prop2Id;
}
在运行时,在内存中,我有:
var L1 = new List<T>();

, L1包含以下T对象:

Prop1   Prop2
12       5
6        7
8        9
10       12 

I 不能做以下操作:

attributes.Where(x=>L1.Any(y=>y.Prop1ID == x.Prop1ID && y.Prop2ID == x.Prop2ID))

attributes是EF类型(即:在DB中)

这不起作用,因为它不能创建T的常值类型——它只期望原语和可枚举对象。

有没有人找出了一个解决方案,而不是带回所有的属性,使他们在内存中的IEnumerable而不是IQueryable?对我来说,这不是一个真正的选择:-(

基于内存中原语组合的查询的实体框架解决方案

)

假设您提供的两个属性是整数类型。所以你可以试试这个变通方法。我们需要将列表转换为另一个字符串键列表,如下所示:

var stringKeys = L1.Select(e => e.Prop1 + "_" + e.Prop2);
//then use stringKeys normally
attributes.Where(x=> stringKeys.Contains(x.Prop1ID + "_" + x.Prop2ID));

如果不是这种情况(不限于整数属性),我们可能不得不以更复杂的方式来做,通过基于列表L1构建Where条件:

var result = attributes;
foreach(var e in L1){
  var k1 = e.Prop1;
  var k2 = e.Prop2;
  var sub = attributes.Where(x => k1 == x.Prop1ID && k2 == x.Prop2ID);      
  result = result.Concat(sub);
}
//then access result instead of attributes

上面的方法可能有点低效。在连接(UNION ALL)所有结果之前,它将对数据库表执行L1.CountWHERE。但是我相信如果在关键列上执行,性能仍然很好。

最后一个解决方案是尝试使用表达式树(表示在Where中传递的谓词):

//suppose your attributes is a set of Attribute
var p = Expression.Parameter(typeof(Attribute));
var p1 = Expression.Property(p, "Prop1ID");
var p2 = Expression.Property(p, "Prop2ID");
var initBool = Expression.Constant(false) as Expression;
//build the BodyExpression for the predicate
var body = L1.Aggregate(initBool, (c,e) => {
               var ep1 = Expression.Constant(e.Prop1);
               var ep2 = Expression.Constant(e.Prop2);
               var and = Expression.And(Expression.Equal(ep1, p1), Expression.Equal(ep2,p2));
               return Expression.Or(c, and); 
           });
attributes.Where(Expression.Lambda<Func<Attribute, bool>>(body, p));

注意,x.Prop1ID的类型应该与L1.Prop1的每个元素的类型完全匹配(例如,应该同时是intfloat,…)。同样的条件适用于所有相应的属性。否则,您需要修改代码来构建表达式树(这里的原因是Expression.Equal要求两个操作数表达式具有相同的数据类型)。我没有测试最后的代码使用表达式树,但它的思想是非常清楚的。

最后一个选项涉及表达式(内部)是尝试使用LinqKit。我甚至没有使用过这个库一次,但它可以帮助您在许多情况下免于构建表达式树。因此,如果它可以帮助您运行原始查询,而不会得到您提到的异常,请尝试一下。