实体框架是否允许你具有筛选的属性?

Does Entity Framework allow you to have filtered properties?

提问人:Pure.Krome 提问时间:11/16/2023 最后编辑:Gert ArnoldPure.Krome 更新时间:11/17/2023 访问量:73

问:

我想知道 EF-Core 是否为我们提供了一个已经使用 where 子句“预筛选”的属性的能力?

例如:

我有一个表 (.. 因此.. .) 每个用户可以有零到多(..因此)。UsersDbSet<User> UsersOrdersDbSet<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。

那么,这可能吗?

C# .NET sql-server-2008 实体框架核心

评论

0赞 user16606026 11/16/2023
如何制作一个 getter 属性,例如 - 不过,在查询时可能需要这样做。MostRecentOrderpublic Order MostRecentOrder => Orders?.FirstOrDefault(o => o is most recent)Include(user => user.Orders)
0赞 Pure.Krome 11/16/2023
我想到了这一点,然后想知道是否总是必须下载所有订单。当我只在最近的订单之后时。(可能有很多订单......而且也有很多客户).Include
0赞 Svyatoslav Danyliv 11/16/2023
可以进行查询,但仅查询属性是行不通的。您还需要接受 DbContext 的函数。看看这个我的答案
1赞 user16606026 11/16/2023
较新的 EF 已过滤 Include,但您是对的,如果有很多订单,简单的 include 和 getter 将导致问题。

答:

-2赞 Radheshyam Shah 11/16/2023 #1

首先,您可以使用以下命令将列表设置为 Id 的降序

OrderByDescending(x => x.Id)

然后使用后

FirstOrDefault() 

您可以获取最新的订单。

或者,如果您想使用一行来设置它,则可以使用以下代码

Order MostRecentOrder = await Orders.OrderByDescending(x => x.OrderId).FirstOrDefault();

评论

0赞 Pure.Krome 11/16/2023
对不起,伙计——我想你误会了。你向我展示的是我如何从数据库中检索数据。这很好,但不是我想问的。我在问我如何在我的类(由 DbSet 表示)上有一个 PROPERTY,它会自动执行此操作。
-1赞 Mehdi Sadeghi 11/17/2023 #2

您可以使用查询过滤器并将其注册到实体配置中的 onModelCreating 重写方法中。

喜欢这个

protected override void OnModelCreating(ModelBuilder modelBuilder)
 {
     modelBuilder.Entity<Order>().HasQueryFilter(
         p => 
         p.MostRecentOrder.hasSpecificCondition()
     );
 }

筛选器将自动应用于检索 Order 实体实例的所有查询。

评论

0赞 JineappleAra 11/17/2023
查询筛选器仅适用于可针对单个实体评估的条件。它不允许仅订购和获取一个实体。最新的订单必须在数据库中有一个额外的标志来标记它。
0赞 Gert Arnold 11/17/2023
请在发布前测试代码。这避免了很多挫败感。
1赞 JineappleAra 11/17/2023 #3

有只允许加载最后一个订单的 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 类返回,但从我的头顶来看,我不确定一个简单的通用解决方案。