你会如何使用LINQ进行“不在”查询?

时间:2008-10-08 17:01:41

标签: c# linq

我有两个集合,在两个集合中都有属性Email。我需要获取第一个列表中的项目列表,其中第二个列表中不存在Email。使用SQL我只会使用“not in”,但我不知道LINQ中的等价物。怎么做的?

到目前为止,我有一个加入,比如......

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

但我不能加入,因为我需要差异,加入会失败。我需要一些使用Contains或Exists的方法我相信。我还没有找到一个例子来做到这一点。

17 个答案:

答案 0 :(得分:314)

您需要Except运算符。

var answer = list1.Except(list2);

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

注意:此技术仅适用于基本类型,因为您必须实现IEqualityComparer以使用具有复杂类型的Except方法。

答案 1 :(得分:278)

我不知道这对你有帮助,但是......

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 );

来自The NOT IN clause in LINQ to SQL Marco Russo

答案 2 :(得分:57)

  

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

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

答案 3 :(得分:55)

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

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

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

答案 4 :(得分:14)

您可以结合使用Where和Any来查找:

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

答案 5 :(得分:8)

您可以将这两个集合放在两个不同的列表中,例如list1和list2。

然后写下

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

这样可行。

答案 6 :(得分:7)

在使用ADO.NET Entity Framework的情况下,EchoStorm的解决方案也可以完美运行。但我花了几分钟时间绕过它。假设你有一个数据库上下文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查询中可以有两个来自。这是一个完整的工作示例,使用列表。每个类Foo和Bar都有一个Id。 Foo有一个“外键”引用Bar via Foo.BarId。该程序选择未链接到相应条形图的所有Foo。

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; }
}

答案 7 :(得分:3)

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};

答案 8 :(得分:2)

虽然Except是答案的一部分,但并非完整答案。默认情况下,Except(与几个LINQ运算符一样)对引用类型进行引用比较。要按对象中的值进行比较,您必须

  • 在您的类型中实施IEquatable<T>,或
  • 在您的类型中覆盖EqualsGetHashCode,或
  • 传入为您的类型
  • 实施IEqualityComparer<T>的类型的实例

答案 9 :(得分:1)

为简单起见使用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());

答案 10 :(得分:1)

也可以使用All()

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

答案 11 :(得分:1)

对于那些也想在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");

答案 12 :(得分:0)

 DynamicWebsiteEntities db = new DynamicWebsiteEntities();
    var data = (from dt_sub in db.Subjects_Details
                                //Sub Query - 1
                            let sub_s_g = (from sg in db.Subjects_In_Group
                                           where sg.GroupId == groupId
                                           select sg.SubjectId)
                            //Where Cause
                            where !sub_s_g.Contains(dt_sub.Id) && dt_sub.IsLanguage == false
                            //Order By Cause
                            orderby dt_sub.Subject_Name

                            select dt_sub)
                           .AsEnumerable();
                  
                                SelectList multiSelect = new SelectList(data, "Id", "Subject_Name", selectedValue);

    //======================================OR===========================================

    var data = (from dt_sub in db.Subjects_Details

                               
                            //Where Cause
                            where !(from sg in db.Subjects_In_Group
                                           where sg.GroupId == groupId
                                           select sg.SubjectId).Contains(dt_sub.Id) && dt_sub.IsLanguage == false

                            //Order By Cause
                            orderby dt_sub.Subject_Name

                            select dt_sub)

                           .AsEnumerable();

答案 13 :(得分:0)

或者,您也可以这样:

var result = list1.Where(p => list2.All(x => x.Id != p.Id));

答案 14 :(得分:0)

您是否无法进行外部联接,只有在该组为空时才从第一个列表中选择项目?类似的东西:

posts_votes

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

答案 15 :(得分:0)

我没有使用LINQ to Entities测试此内容:

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 );

答案 16 :(得分:0)

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

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

'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