C# 基于导航属性的LINQ过滤器
我有以下两个实体:C# 基于导航属性的LINQ过滤器,c#,entity-framework,linq,C#,Entity Framework,Linq,我有以下两个实体: public class Person { public Person() { Items = new HashSet<Item>(); } public string Id { get; set; } public string Name { get; set; } public ICollection<Item> Items { get; private set; } } p
public class Person
{
public Person()
{
Items = new HashSet<Item>();
}
public string Id { get; set; }
public string Name { get; set; }
public ICollection<Item> Items { get; private set; }
}
public class Item
{
public string Id { get; set; }
public DateTime Date { get; set; }
public string Status { get; set; }
public Person Person { get; set; }
public string PersonId { get; set; }
}
但EF Core显然无法做到这一点。项目集合将非常大>20000,因此不希望为每个人加载所有项目。
我应该怎么做?是的,很遗憾,您不能以这种方式使用Include扩展方法,但如果您愿意使用第三方库,我建议您使用该库,您可以使用该库:
var persons = _context.Persons
.IncludeFilter(e => e.Items.OrderByDescending(i => i.Date).Take(1))
.ToList();
有第二个选择可以使用,但我认为第一个解决方案是接近你所寻找的
第三个选项是使用预期结果投影查询:
var persons = _context.Persons
.Select(e=> new {Person=e,
Item=e.Items.OrderByDescending(i => i.Date)
.Take(1)
})
.ToList();
是的,不幸的是你误用了Include 不过,对于查询,您可以对项目使用GroupBy和子查询 查询按PersonId分组、按组内日期排序的项目,并首先获取这些项目 希望您有一些相关的索引来加速数据库端的查询 应该是这样的:
_context.Items.GroupBy(i => i.PersonId)
.Select(g => g.OrderByDescending(p => p.Date).FirstOrDefault())
你没有在物品类中遗漏像PersonId这样的东西吗?你是对的@PeterSchneider。我没有完全复制实体类。我现在编辑了这个。我不完全理解@Sinatr。如果我简单地说_context.Persons.Includee=>e.Items.ToList;,它将加载此列表中的所有项目,对吗?是的,很遗憾您误用了Include。对于查询,请使用Where并直接选择OrderBy。Include用于应在结果中加载的实体。您不能在include中执行一些复杂的子查询。一如既往:使用投影新{…}。谢谢!我曾考虑过查询项目列表,但有可能某人没有任何项目,在其中我仍然希望返回此人,但项目列表为空。我是否可以将此查询与_context.Persons.Includee=>e.Items.ToList组合;在某种程度上?此外,索引应该在项目上。PersonId?关于索引:是的,索引应该在PersonId上,然后按您期望的顺序在日期上。关于没有项目的人,不幸的是,这种方法只会给至少有一个项目链接的人。您还可以检索所有未链接任何项目的人员,从表项目中选择所有唯一的personId,然后选择id不在此列表中的人员,但我不确定其性能,可能还有另一种更简单的方法。啊,你可以用上面对项目的查询结果做一个人员的左连接。当然,我缺少了你需要的实际投影:我不想在单个查询中使用更多的第三方库。关于第三个选项,有没有一种简单的方法来检索p.Items=persons.Items的Person对象?嗨@laurensvm,对不起,我不太理解这个问题,但是如果你问我是否可以用查询项目的结果投影一个新的Person对象,那么没有,EF不会允许你这么做,我想我会重写我的代码来使用你的第三个选项。谢谢你的帮助!
_context.Items.GroupBy(i => i.PersonId)
.Select(g => g.OrderByDescending(p => p.Date).FirstOrDefault())