提问人:Pure.Krome 提问时间:11/16/2023 最后编辑:Gert ArnoldPure.Krome 更新时间:11/17/2023 访问量:73
实体框架是否允许你具有筛选的属性?
Does Entity Framework allow you to have filtered properties?
问:
我想知道 EF-Core 是否为我们提供了一个已经使用 where 子句“预筛选”的属性的能力?
例如:
我有一个表 (.. 因此.. .)
每个用户可以有零到多(..因此)。Users
DbSet<User> Users
Orders
DbSet<Order> Orders
因此,用户将如下所示:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; }
}
所以现在我想要一个属性是 最新订单:
例如
public Order MostRecentOrder { get; set; }
这将由硬编码规则决定:最新的订单。
这可能吗?
否则,我觉得我必须在我编写的每个 EF 核心查询中都包含此 LINQ 查询,其中我关心此属性。
另外,我曾经尝试过制作一个扩展方法,但 EF 查询生成器或其他东西崩溃了,说它无法将其转换为 SQL。
那么,这可能吗?
答:
首先,您可以使用以下命令将列表设置为 Id 的降序
OrderByDescending(x => x.Id)
然后使用后
FirstOrDefault()
您可以获取最新的订单。
或者,如果您想使用一行来设置它,则可以使用以下代码
Order MostRecentOrder = await Orders.OrderByDescending(x => x.OrderId).FirstOrDefault();
评论
您可以使用查询过滤器并将其注册到实体配置中的 onModelCreating 重写方法中。
喜欢这个
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().HasQueryFilter(
p =>
p.MostRecentOrder.hasSpecificCondition()
);
}
筛选器将自动应用于检索 Order 实体实例的所有查询。
评论
有只允许加载最后一个订单的 Filtered Include 和 Auto Include。不幸的是,目前它们无法合并(https://github.com/dotnet/efcore/issues/30883)
作为替代方案,您可以做些什么:
在用户类上创建属性作为 getter:
public Order? MostRecentOrder => this.Orders.OrderByDesc(o => o.CreatedOn).FirstOrDefault()
在 DbContext 上创建一个方法,返回应用了 include 的 IQueryable for Users:
public IQueryable<User> UserWithOrder() {
return this.Users.Include(u => u.Orders.OrderByDesc(o => o.CreatedOn).Take(1))
}
然后,您应该始终使用该方法来访问用户。直接使用 DbSet 并访问 MostRecentOrder 属性仍会导致异常。
如果你想要编译时的安全性,你也许可以通过创建一个具有此属性的额外类来使一些东西起作用,该类直接从方法而不是 User 类返回,但从我的头顶来看,我不确定一个简单的通用解决方案。
评论
MostRecentOrder
public Order MostRecentOrder => Orders?.FirstOrDefault(o => o is most recent)
Include(user => user.Orders)
.Include