实际上,我的一位同事问了我这个问题,但我还没有找到答案。到此为止。
给定一个有2个外键的实体,比如说
public class MyTable
{
public int Key1 { get; set; }
public int Key2 { get; set; }
}
和2个列表
public ICollection List1 => new List<int> { 1, 2, 3 };
public ICollection List2 => new List<int> { 4, 5, 6 };
他需要查询Key1与List1中的值匹配的所有记录,而Key2与List2中的值匹配,例如:
Key1 == 1 && Key2 == 4
也就是说,他想检查List1和List2,(1,4),(2,5)和(3,6)中的任何给定元组。
EF有直接的方法吗?
答案 0 :(得分:1)
试试这个:
static IQueryable<TSource> WhereIn(this Table<TSource> table, List<object[]> list) where TSource : class
{
var query = table.AsQueryable();
foreach (object[] item in list)
{
Expression<Func<TSource, bool>> expr = WhereInExpression(item);
query = query.Where(expr);
}
return query;
}
static Expression<Func<TSource, bool>> WhereInExpression<TSource>(object[] item)
{
ParameterExpression parameterItem = Expression.Parameter(typeof(TSource), "expr");
BinaryExpression filter1 = Expression.Equal(LambdaExpression.PropertyOrField(parameterItem, "Key1"),
Expression.Constant(item[0]));
BinaryExpression filter2 = Expression.Equal(LambdaExpression.PropertyOrField(parameterItem, "Key2"),
Expression.Constant(item[1]));
BinaryExpression filter = LambdaExpression.And(filter1, filter2);
var expr = Expression.Lambda<Func<TSource, bool>>(filter, new ParameterExpression[] { parameterItem });
expr.Compile();
return expr;
}
用法:
List<object[]> list = new List<object[]>() { new object[] { 1, 100 }, new object[] { 1, 101 }, new object[] { 2, 100 } };
var result = db.MyTable.WhereIn<MyTable>(list);
答案 1 :(得分:1)
您可以设置for
循环来捕获Where
中的一些局部变量(在每个循环中)并使用Concat
(或Union
- 可能性能更差)总结这样的结果:
IQueryable<MyTable> q = null;
//suppose 2 lists have the same count
for(var i = 0; i < list1.Count; i++){
var k1 = list1[i];
var k2 = list2[i];
var s = context.myTables.Where(e => e.Key1 == k1 && e.Key2 == k2);
q = q == null ? s : q.Concat(s);
}
//materialize the result
var result = q.ToList();
注意: 我们可以在这里使用Concat
因为每个子结果应该是唯一的(基于搜索键)。它肯定比Union
具有更好的性能(确保唯一性,而我们已经知道子结果事先都是独特的 - 所以它是不必要的)。
如果你有一个int
列表(只是整数),你也可以将这些键配对成下划线字符串并使用Contains
通常如下:
var stringKeys = list1.Select((e,i) => e + "_" + list2[i]).ToList();
var result = context.myTables.Where(e => stringKeys.Contains(e.Key1 + "_" + e.Key2))
.ToList();
构建表达式树也是另一种方法,但它更复杂,而我不确定它是否具有更好的性能。
答案 2 :(得分:0)
确认使用Entity框架
var tuples = List1.Cast<int>().Zip(List2.Cast<int>(), (l, r) => new { l, r });
var results = Orders.Where(o =>
tuples.Contains(new { l = (int)o.KeyOne, r = (int)o.KeyTwo })
);
或者更简单,如果您将列表定义为ICollection<int>
或IList<int>
(等等):
var tuples = List1.Zip(List2, (l, r) => new { l, r });
var results = Orders.Where(o =>
tuples.Contains(new { l = (int)o.KeyOne, r = (int)o.KeyTwo })
);
答案 3 :(得分:-1)
在这里小提琴:https://dotnetfiddle.net/YyyZBY
var List_1 = new List<int> { 1, 2, 3 };
var List_2 = new List<int> { 4, 5, 6 };
var TargetList = new List<MyTable>();
var index1=0;
var List1 = List_1.Select(x=>new { ind=index1++,value=x });
var index2=0;
var List2 = List_2.Select(x=>new { ind=index2++,value=x });
var values = from l1 in List1
join l2 in List2 on l1.ind equals l2.ind
select new {value1=l1.value,value2=l2.value };
var result = TargetList.Where(x=>values.Any(y=>y.value1==x.Key1&&y.value2==x.Key2));