您将如何使用 LINQ 执行“不在”查询

本文关键字:不在 查询 执行 LINQ 何使用 | 更新日期: 2023-09-27 17:48:51

我有两个集合,它们在两个集合中都有属性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 };

但是我无法加入,因为我需要差异并且加入会失败。我需要某种方式来使用我相信包含或存在。我只是还没有找到一个例子来做到这一点。

您将如何使用 LINQ 执行“不在”查询

您需要 except 运算符。

var answer = list1.Except(list2);

更好的解释在这里:https://learn.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 中的 NOT IN 子句到 SQL 作者: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));
也可以

使用All()

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

在使用 ADO.NET 实体框架的情况下,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的"外键"引用。程序选择所有未链接到相应栏的 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));

这将起作用。

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>类型的实例
或者,

您可以这样做:

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

简单起见,使用 List of 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");

我没有用 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)

我不确定这是否会以任何有效的方式与实体框架一起使用。

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