簡體   English   中英

您將如何使用 LINQ 進行“不在”查詢?

[英]How would you do a “not in” query with 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 };

但是我無法加入,因為我需要差異並且加入會失敗。 我需要某種方式來使用我相信的“包含”或“存在”。 我只是還沒有找到一個例子來做到這一點。

您需要“除外”運算符。

var answer = list1.Except(list2);

更好的解釋在這里: https : //docs.microsoft.com/archive/blogs/charlie/linq-farm-more-on-set-operators

注意:此技術僅適用於原始類型,因為您必須實現IEqualityComparer才能對復雜類型使用Except方法。

我不知道這是否對你有幫助,但是..

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 中的 NOT IN 子句by Marco Russo

對於從一組內存對象開始並查詢數據庫的人來說,我發現這是最好的方法:

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

這會在 SQL 中生成一個很好的WHERE ... IN (...)子句。

第一個列表中的項目,而第二個列表中不存在電子郵件。

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

您可以使用 Where 和 Any 的組合來查找不在:

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

在使用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 查詢中可以有兩個 from。 這是一個完整的工作示例,使用列表。 每個類,Foo 和 Bar,都有一個 Id。 Foo 通過 Foo.BarId 對 Bar 有一個“外鍵”引用。 該程序選擇所有未鏈接到相應 Bar 的 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; }
}

您可以將兩個集合放在兩個不同的列表中,比如 list1 和 list2。

然后就寫

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

這將起作用。

也可以使用All()

var notInList = list1.Where(p => list2.All(p2 => p2.Email != p.Email));
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};

雖然Except是答案的一部分,但並不是全部答案。 默認情況下, Except (像一些 LINQ 運算符一樣)對引用類型進行引用比較。 要按對象中的值進行比較,您必須

  • 在您的類型中實現IEquatable<T> ,或
  • 在您的類型中覆蓋EqualsGetHashCode ,或
  • 為您的類型傳入一個實現IEqualityComparer<T>的類型的實例

為簡單起見,使用 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());

對於還想在 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");

或者,您可以這樣做:

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

我沒有使用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 );

如果組為空,您不能進行外部聯接,僅從第一個列表中選擇項目嗎? 就像是:

Dim result = (From a In list1
              Group Join b In list2 
                  On a.Value Equals b.Value 
                  Into grp = Group
              Where Not grp.Any
              Select a)

我不確定這是否會以任何有效的方式與實體框架一起使用。

謝謝布雷特。 你的建議對我也有幫助。 我有一個對象列表,並想使用另一個對象列表過濾該對象。 再次感謝....

如果有人需要,請查看我的代碼示例:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM