你会怎么做一个“not in”;查询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 };

但我不能加入,因为我需要的差异和连接将失败。我需要一些方法使用包含或存在我相信。我只是还没有找到这样做的例子。

376847 次浏览

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

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

from LINQ to SQL中的NOT IN子句 by 马可·鲁索

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运算符。

var answer = list1.Except(list2);

更好的解释在这里:https://learn.microsoft.com/archive/blogs/charlie/linq-farm-more-on-set-operators

此技术仅适用于基本类型,因为必须实现IEqualityComparer才能对复杂类型使用Except方法。

为简单起见,使用int类型List的示例。

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

在第一个列表中,电子邮件在第二个列表中不存在。

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

虽然Except是答案的一部分,但它不是全部答案。默认情况下,Except(像几个LINQ操作符一样)对引用类型进行引用比较。要通过对象中的值进行比较,必须这样做

  • 在你的类型中实现IEquatable<T>,或者
  • 在你的类型中覆盖EqualsGetHashCode,或者
  • 传入一个为你的类型实现IEqualityComparer<T>的类型实例

在使用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有一个“外键”引用。程序选择所有未链接到相应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; }
}

对于那些从一组内存对象开始并对数据库进行查询的人来说,我发现这是最好的方法:

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

这将在SQL中生成一个漂亮的WHERE ... IN (...)子句。

你可以在两个不同的列表中取两个集合,比如list1和list2。

然后就写

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

这是可行的。

我没有使用LINQ 用实体测试这个:

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

你可以使用Where和Any的组合来查找not in:

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

如果组为空,就不能做一个外部连接,只从第一个列表中选择项目吗?喜欢的东西:

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)

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

对于任何想要在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");

也可以使用All()

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

或者你可以这样做:

var result = list1.Where(p => list2.All(x => x.Id != p.Id));
 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();