基本上我要做的是获取一个对象列表并根据一些标准对其进行过滤,其中一个标准是该键在另一个列表中不存在。这是一个例子:
我的两个类与此类似:
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< Test>进行排序通过查看课程并确保列表< Appointment>中不存在测试。在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)
但是,我无法弄清楚如何在LINQ中执行此操作。有什么想法吗?
答案 0 :(得分: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));
以下内容稍微简单易懂:
var query = tests.Where(t => !appts.Any(a => a.testName == t.name));
但第一个版本会更快,因为Join
函数将计算匹配的哈希表,而不是对appts
中每个元素的tests
列表进行线性搜索
答案 1 :(得分:4)
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提供了一个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 ON的结果。第一个结果是使用NOT IN子句的手写查询。第二个结果是LINQ to SQL生成的查询。