LINQ to Entities .Contains 元组(2 个外键)

Tho*_*der 7 c# linq entity-framework

其实,我的一个同事问过我这个问题,我一直没能想出答案。开始。

给定一个有 2 个外键的实体,比如说

public class MyTable
{
   public int Key1 { get; set; }
   public int Key2 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和 2 个列表

public ICollection List1 => new List<int> { 1, 2, 3 };
public ICollection List2 => new List<int> { 4, 5, 6 };
Run Code Online (Sandbox Code Playgroud)

他需要查询 Key1 与 List1 中的值匹配且 Key2 与 List2 中的值匹配的所有记录,例如

Key1 == 1 && Key2 == 4
Run Code Online (Sandbox Code Playgroud)

也就是说,他想检查 List1 和 List2 中的任何给定元组,(1, 4), (2, 5) 和 (3, 6)。

EF 中是否有一种直接的方法可以做到这一点?

Hop*_*ess 3

您可以创建一个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();
Run Code Online (Sandbox Code Playgroud)

注意:我们可以在此处使用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();
Run Code Online (Sandbox Code Playgroud)

构建表达式树也是另一种方法,但它更复杂,而且我不确定它是否具有更好的性能。