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

leg*_*ass 4 c# 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;
}
Run Code Online (Sandbox Code Playgroud)

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

SELECT new Group<Test>(c.Key, c)
FROM tests in testList
WHERE tests.Course != "Science"
AND tests.name NOT IN (SELECT testName FROM appotList)
Run Code Online (Sandbox Code Playgroud)

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

Ada*_*son 10

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

List<Test> tests = ...;
List<Appointment> appts = ...;

var query = tests.Except(
            tests.Join(appts, t => t.name, a => a.testName, (t, a) => t));
Run Code Online (Sandbox Code Playgroud)

以下内容略微简单易读:

var query = tests.Where(t => !appts.Any(a => a.testName == t.name));
Run Code Online (Sandbox Code Playgroud)

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


Jak*_*cki 5

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]
)
Run Code Online (Sandbox Code Playgroud)

这不是获得所需结果的更快方法(使用 NOT EXISTS 是最喜欢的方法 - 稍后将详细介绍)。LINQ 提供了 Contains 扩展方法,允许编写以下代码。

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 );
Run Code Online (Sandbox Code Playgroud)

在 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]
    ))
Run Code Online (Sandbox Code Playgroud)

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