LINQ to Entities。包含一个元组(2个外键)

时间:2015-09-25 06:03:57

标签: c# entity-framework linq

实际上,我的一位同事问了我这个问题,但我还没有找到答案。到此为止。

给定一个有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有直接的方法吗?

4 个答案:

答案 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));