LINQ查询:根据键确定一个列表中的对象是否存在于另一个列表中

基本上我要做的是获取一个对象列表并根据一些标准对其进行过滤,其中一个标准是该键在另一个列表中不存在。 这是一个例子:
我的两个类与此类似:

public class Test { public string name; public string instructor_name; public string course; } public class Appointment { public string site; public DateTime forWhen; public string testName; } 

我想通过查看课程并确保List 中不存在测试来对List 进行排序。 在SQL中我会这样做:

 SELECT new Group(c.Key, c) FROM tests in testList WHERE tests.Course != "Science" AND tests.name NOT IN (SELECT testName FROM appotList) 

但是,我无法弄清楚如何在LINQ中执行此操作。 有任何想法吗?

http://introducinglinq.com/blogs/marcorusso/archive/2008/01/14/the-not-in-clause-in-linq-to-sql.aspx

请考虑此代码,该代码返回Orders表中没有订单的所有客户。 这是一个返回该值的SQL查询。

 SELECT * FROM [dbo].[Customers] AS [t0] WHERE [t0].[CustomerID] NOT IN ( SELECT [t1].[CustomerID] FROM [dbo].[Orders] AS [t1] ) 

这不是获得所需结果的更快方法(使用NOT EXISTS是最喜欢的方式 – 更多关于这一点)。 LINQ提供了一个包含扩展方法,允许编写以下代码。

 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 to SQL中,查询被转换为此SQL代码:

 SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE NOT (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Orders] AS [t1] WHERE [t1].[CustomerID] = [t0].[CustomerID] )) 

这种方法不仅在语义上等同,而且执行速度更快。 以下是SET STATISTICS IO ON的结果。 第一个结果是使用NOT IN子句的手写查询。 第二个结果是LINQ to SQL生成的查询。

如果您正在谈论执行客户端过滤,那么使用LINQ to Objects非常容易。 像这样的东西:

 List tests = ...; List appts = ...; var query = tests.Except( tests.Join(appts, t => t.name, a => a.testName, (t, a) => t)); 

以下内容稍微简单易读:

 var query = tests.Where(t => !appts.Any(a => a.testName == t.name)); 

但是第一个版本会更快,因为Join函数将计算匹配的哈希表,而不是对tests每个元素进行appts列表的线性搜索。