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

C# LINQ查询:根据键确定一个列表中的对象是否存在于另一个列表中,c#,linq,C#,Linq,基本上,我要做的是获取一个对象列表,并根据一些条件对其进行过滤,其中一个条件是键不存在于另一个列表中。下面是一个例子: 我的两个课程与此类似: public class Test { public string name; public string instructor_name; public string course; } public class Appointment { public string site; public Da

基本上,我要做的是获取一个对象列表,并根据一些条件对其进行过滤,其中一个条件是键不存在于另一个列表中。下面是一个例子: 我的两个课程与此类似:

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;
}
我想通过查看课程并确保列表中不存在测试来对列表进行排序。在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)
List<Test> tests = ...;
List<Appointment> appts = ...;

var query = tests.Except(
            tests.Join(appts, t => t.name, a => a.testName, (t, a) => t));
然而,我不知道在LINQ我会怎么做。有什么想法吗

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

SELECT *
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CustomerID] NOT IN (
    SELECT [t1].[CustomerID]
    FROM [dbo].[Orders] AS [t1]
)
这不是使用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 );
在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时的结果。第一个结果是使用NOT IN子句的手写查询。第二个结果是LINQtoSQL生成的查询。

如果您说的是执行客户端过滤,那么使用LINQtoSQL对象非常容易。大概是这样的:

SELECT new Group<Test>(c.Key, c)
FROM tests in testList
WHERE tests.Course != "Science"
AND tests.name NOT IN (SELECT testName FROM appotList)
List<Test> tests = ...;
List<Appointment> appts = ...;

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

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

您可能想看看SQL的第一行……它不是SQL:我意识到这一点,但我不想在SQL中这样做。这正是我在SQL中使用的格式。我这样写是为了让人们更好地了解我在LINQ中要做的事情。除非我误读了这个问题,否则他似乎在问如何进行客户端过滤,即LINQ对对象,而不是如何进行客户端过滤SQL@Adam-LINQ查询仍然应该工作,不是吗?而不是dc.Customers和dc.Orders,他可以使用他的对象集合。这实际上是我要找的信息。我一定已经搜索了3打教程和文档网站,但从未找到任何与此相关的内容。正是我所需要的。谢谢第二个答案对我来说更有意义,所以我决定用它,但我对你的帖子很好奇。可以在Where方法中创建多个选择条件吗?我希望能够比较测试的日期,看看是否可以参加测试,并检查以确保没有预约。在使用=>运算符时,我还是个新手,因此我不确定如何列出多个条件。@legacybass:是的,可以在Where部分包含任意多个条件。我发布了这个版本,因为它更简单、更快,如果你使用内存中的对象列表,而不是创建一个数据库查询,那么它们会被逗号或分号分隔吗?如何在联接方法中使用多个条件?这是我最感兴趣学习如何使用的一个。@legacybass:不幸的是,连接函数不如where强大。它的工作原理是创建一个简单的哈希表,通过一个值链接两行。您可以在多个条件上进行联接,但只能在跨列进行简单的相等性比较时进行联接。如果您想要一个具体的例子,最好再问一个关于如何在join子句中执行多个条件的问题,我很乐意回答:注意区分大小写:var query=tests.Wheret=>!appts.Anya=>a.testName.ToLower==t.name.ToLower;