按具有布尔值 属性 的对象 属性 过滤

Filtering by object property that has a boolean property

我有以下对象:

public class Item 
{
  public int Id {get; set;}
  public Process Process {get; set;}
}

public class Process
{
  public bool Alive {get; set;}
}

我正在尝试这样做:

context.DB.Items
  .Include(x => x.Process)
  .Where(x => x.Process.Alive);

但是过滤总是让我得到 Process.Alive 为假的项目。

按 属性 过滤的最佳方法是什么,该 属性 包含在作为主要项目的 属性 的对象中?

借助 EF Core,您可以对 one-off 查询使用筛选的 Include

context.DB.Items
   .Include(x => x.Process  
      .Where(x => x.Process.Alive));

或使用全局查询过滤器告诉 EF 只获取“有效”记录:

https://docs.microsoft.com/en-us/ef/core/querying/filters

对于 EF6,使用 Include 预加载集合表示该实体的完整数据状态。过滤后的包含可能会产生误导,因为它们不一定代表任何给定时间点的数据域状态的完整图片。

如果您通常只想处理活动行,例如查看结果等,则可以通过投影进行管理。例如,如果我有一个视图,我想在其中显示一个项目及其进程,我将有一个 ItemViewModel 和一个 ProcessViewModels 集合,只显示我的视图关心的数据。当我投射那个视图模型时:

var item = context.Items
    .Select(x => new ItemViewModel
    {
        ItemId = x.ItemId,
        // ....
        Processes = x.Processes
            .Where(x => x.Alive)
            .Select(p => new ProcessViewModel
            {
                ProcessId = p.ProcessId,
                // ...
            }).ToList()
    }).Single(x => x.ItemId == itemId);

这可以使用 Automapper 和它的 ProjectTo 方法进行简化和集中,这样您就可以配置 Automapper 映射以遵循“活动”活动状态,然后您的查询就像:

var item = context.Items
    .ProjectTo<ItemViewModel>(config)
    .Single(x => x.ItemId == itemId);

其中“config”是一个 MapperConfiguration,其中包含有关如何将 Item 映射到 ItemViewModel 以及将 Process 映射到 ProcessViewModel 的详细信息。 Automapper 负责剩下的工作,将必要的细节投射到 EF 中以生成合适的 SQL 语句。

如果您确实想使用实体来执行更新和引用详细信息,那么您可以投影一个匿名类型:

var itemsAndAliveProcesses = context.Db.Items
   .Select(x => new 
   {
       Item = x,
       AliveProcesses = x.Processes.Where(p => p.Alive).ToList()
   }).Single(x => x.ItemId == itemId);

在这里您可以使用 itemsAndAliveProcesses.AliveProcesses 来访问该项目的活动进程,而不是 .Item.Processes 如果您可以将其留给 lazy-load 或 eager-load确实想访问整个集合。

我建议投影优于过滤 Include,因为利用投影会导致比加载整个实体图更有效的查询,并且它有助于确保当您使用实体图时,这些方法可以始终如一地期望接收数据状态的完整或可完成的表示。 (而不是过滤子集,因为您可以在 任何东西 上过滤 Include