你将如何做一个“不在”查询与LINQ?

我有两个集合在两个集合中都有属性Email 。 我需要获得第一个列表中Email不存在于第二个列表中的项目列表。 使用SQL,我只是使用“不在”,但我不知道在LINQ中的等效。 这是怎么做的?

到目前为止,我有一个join,如…

 var matches = from item1 in list1 join item2 in list2 on item1.Email equals item2.Email select new { Email = list1.Email }; 

但我不能join,因为我需要的差异和联接将失败。 我需要一些使用Contains或Exists的方式,我相信。 我还没有find一个这样做的例子。

我不知道这是否会帮助你,但..

 NorthwindDataContext dc = new NorthwindDataContext(); dc.Log = Console.Out; var query = from c in dc.Customers where !(from o in dc.Orders select o.CustomerID) .Contains(c.CustomerID) select c; foreach (var c in query) Console.WriteLine( c ); 

从LINQ的NOT IN子句到 Marco Russo的 SQL

你需要Except运算符。

 var answer = list1.Except(list2); 

这里更好的解释: http : //blogs.msdn.com/charlie/archive/2008/07/12/the-linq-set-operators.aspx

注:这种技术只适用于原始types,因为您必须实现一个iEqualityComparor才能使用复杂types的Except方法。

第一个列表中邮件不存在于第二个列表中的项目。

 from item1 in List1 where !(list2.Any(item2 => item2.Email == item1.Email)) select item1; 

对于从一组内存对象开始并且正在查询数据库的人来说,我发现这是最好的方法:

 var itemIds = inMemoryList.Select(x => x.Id).ToArray(); var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id)); 

这在SQL中产生了一个很好的WHERE ... IN (...)子句。

您可以使用Where和Any的组合来查找不在:

 var NotInRecord =list1.Where(p => !list2.Any(p2 => p2.Email == p.Email)); 

你可以把这两个集合放在两个不同的列表中,比如list1和list2。

那就写吧

 list1.RemoveAll(Item => list2.Contains(Item)); 

这将工作。

在使用ADO.NETentity framework的情况下,EchoStorm的解决scheme也可以很好地工作。 但是花了我几分钟的时间才把头围上。 假设你有一个数据库上下文dc,并且希望查找表x中没有链接到表y中的行,那么完整答案的答案如下所示:

 var linked = from x in dc.X from y in dc.Y where x.MyProperty == y.MyProperty select x; var notLinked = dc.X.Except(linked); 

对于Andy的评论,是的,在LINQ查询中可以有两个from。 这是一个完整的工作示例,使用列表。 每个class级Foo和Bar都有一个Id。 Foo有一个通过Foo.BarId的Bar的“外键”引用。 程序select所有Foo没有链接到相应的Bar。

 class Program { static void Main(string[] args) { // Creates some foos List<Foo> fooList = new List<Foo>(); fooList.Add(new Foo { Id = 1, BarId = 11 }); fooList.Add(new Foo { Id = 2, BarId = 12 }); fooList.Add(new Foo { Id = 3, BarId = 13 }); fooList.Add(new Foo { Id = 4, BarId = 14 }); fooList.Add(new Foo { Id = 5, BarId = -1 }); fooList.Add(new Foo { Id = 6, BarId = -1 }); fooList.Add(new Foo { Id = 7, BarId = -1 }); // Create some bars List<Bar> barList = new List<Bar>(); barList.Add(new Bar { Id = 11 }); barList.Add(new Bar { Id = 12 }); barList.Add(new Bar { Id = 13 }); barList.Add(new Bar { Id = 14 }); barList.Add(new Bar { Id = 15 }); barList.Add(new Bar { Id = 16 }); barList.Add(new Bar { Id = 17 }); var linked = from foo in fooList from bar in barList where foo.BarId == bar.Id select foo; var notLinked = fooList.Except(linked); foreach (Foo item in notLinked) { Console.WriteLine( String.Format( "Foo.Id: {0} | Bar.Id: {1}", item.Id, item.BarId)); } Console.WriteLine("Any key to continue..."); Console.ReadKey(); } } class Foo { public int Id { get; set; } public int BarId { get; set; } } class Bar { public int Id { get; set; } } 
 var secondEmails = (from item in list2 select new { Email = item.Email } ).ToList(); var matches = from item in list1 where !secondEmails.Contains(item.Email) select new {Email = item.Email}; 

Except答案的一部分,这不是全部的答案。 默认情况下, Except (与几个LINQ运算符一样)对引用types进行引用比较。 要通过对象中的值进行比较,您必须

  • 在你的types中实现IEquatable<T> ,或者
  • 在你的types中覆盖EqualsGetHashCode ,或者
  • 传入一个实现IEqualityComparer<T>的types的实例

为简单起见,使用int列表的示例。

 List<int> list1 = new List<int>(); // fill data List<int> list2 = new List<int>(); // fill data var results = from i in list1 where !list2.Contains(i) select i; foreach (var result in results) Console.WriteLine(result.ToString()); 

对于任何想在C#中使用类似SQL的IN操作符的人,请下载这个包:

Mshwf.NiceLinq

它有InNotIn方法:

 var result = list1.In(x => x.Email, list2.Select(z => z.Email)); 

即使你可以这样使用它

 var result = list1.In(x => x.Email, "a@b.com", "b@c.com", "c@d.com"); 

谢谢布雷特 你的build议也帮助了我。 我有一个对象的列表,并希望过滤使用另一个对象列表。 再次感谢….

如果有人需要,请看看我的代码示例:

 'First, get all the items present in the local branch database Dim _AllItems As List(Of LocalItem) = getAllItemsAtBranch(BranchId, RecordState.All) 'Then get the Item Mappings Present for the branch Dim _adpt As New gItem_BranchesTableAdapter Dim dt As New ds_CA_HO.gItem_BranchesDataTable _adpt.FillBranchMappings(dt, BranchId) Dim _MappedItems As List(Of LocalItem) = (From _item As LocalItem In _AllItems Join _ dr As ds_CA_HO.gItem_BranchesRow In dt _ On _item.Id Equals dr.numItemID _ Select _item).ToList _AllItems = _AllItems.Except(_MappedItems.AsEnumerable).ToList Return _AllItems 

我没有用LINQ to Entitiestesting这个:

 NorthwindDataContext dc = new NorthwindDataContext(); dc.Log = Console.Out; var query = from c in dc.Customers where !dc.Orders.Any(o => o.CustomerID == c.CustomerID) select c; 

或者:

 NorthwindDataContext dc = new NorthwindDataContext(); dc.Log = Console.Out; var query = from c in dc.Customers where dc.Orders.All(o => o.CustomerID != c.CustomerID) select c; foreach (var c in query) Console.WriteLine( c ); 

难道你不能做一个外部连接,只有从第一个列表中select项目,如果该组是空的? 就像是:

 Dim result = (From a In list1 Group Join b In list2 On a.Value Equals b.Value Into grp = Group Where Not grp.Any Select a) 

我不确定这是否会以任何有效的方式与entity framework一起工作。

也可以使用All()

 var notInList = list1.Where(p => list2.All(p2 => p2.Email != p.Email));