是否有办法自定义实体查询的默认行为

本文关键字:默认 查询 实体 自定义 是否 | 更新日期: 2023-09-27 17:53:35

我有两个表,其中一个是自引用的:

Job (id, description)
JobAssembly (id, jobid, parentassemblyid)

我有两个类似的域对象:

public class Job
{
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual List<JobAssembly> Assemblies { get; set; }
}
public class JobAssembly
{
    public int Id { get; set; }
    public int JobId { get; set; }
    public virtual Job { get; set; }
    public int? ParentAssemblyId { get; set; }
    public virtual JobAssembly ParentAssembly { get; set; }
    public virtual List<JobAssembly> SubAssemblies { get; set; }
}

问题在这里。当我使用EF:

using (var db = new JobContext())
{
     var job = db.Jobs.Find(1);
}
如我所料,我得到了要求的工作。但它是所有组件都有的——不仅仅是父组件,还有子组件。

我的问题是:我如何指示EF只引入没有子组件的JobAssemblies…作为默认行为?我知道如何查询EF说父程序集。但是,是否有一种方法可以设置映射,或者其他方式,将默认查询行为设置为仅获取parentassemblyid == null的程序集?

谢谢:)编辑:

请允许我举例说明:

我有一个id = 1的Job。它有一个id = 1的Assembly。汇编1有两个子汇编,分别为id = 2和3。当执行var job = db.Jobs.Find(1)时,EF像这样填充对象图:

作业包含所有三个程序集(因为所有三个程序集上的jobid == 1)。id为1的JobAssembly将适当地填充其子程序集。

所有这些都是预期的,但如果我能自定义EF加载对象的方式就更好了。Job不应该有JobId == 1的每个JobAssembly,而应该只有JobId == 1和ParentAssemblyId == null的JobAssembly。

是否有办法自定义实体查询的默认行为

如果我没理解错的话,你想要Job。程序集,只包含那些没有父程序集(即那些程序集是作业的直接子程序集,而不是孙子程序集等)。

这样做的"正常"方法是只让直接子节点通过外键引用Job,并且让孙辈等只引用他们的父母。

在我看来,assembly表被这样创建是为了优化数据读取(也就是说,你只需要在JobId上查询一次,然后你可以在内存中创建树结构)。我将假设就是这种情况,而不是告诉您更改数据库结构。如果不是这样,请告诉我。

有几种方法可以只获得Job的直接子对象。最简单的方法是让Job类的属性为您进行过滤:-

public class Job
{
  public int Id { get; set; }
  public string Description { get; set; }
  public virtual List<JobAssembly> Assemblies { get; set; }
  public IEnumerable<JobAssembly> DirectChildren
  {
    get
    {
      return this.Assemblies == null
        ? null
        : this.Assemblies.Where(x => x.ParentAssemblyId == null);
    }
  }
}

,但如果你要采用这种方法,你需要非常非常小心,不要以一种愚蠢的方式延迟加载数据。有些人在遇到问题时,会想"我知道,我会使用O/RM"。现在他们有N+1个问题;)

一个更健壮的解决方案是使用一个单独的ViewModel来封装应用程序层中所需的树形结构。这可以防止Select N+1问题,因为数据层负责在单个查询中提取整个程序集列表,然后将它们映射到应用程序层的树中:-

public class JobViewModel
{
  public int Id { get; set; }
  public string Description { get; set; }
  public virtual List<JobAssemblyViewModel> Children { get; set; }
}
public class JobAssemblyViewModel
{
  public int Id { get; set; }
  public virtual List<JobAssemblyViewModel> Children { get; set; }
}

如果你经常这样做,你可以考虑使用例如AutoMapper来为你的视图模型投射你的查询。

这是一个使用继承来区分RootAssemblies和SubAssemblies的想法:

public abstract class JobAssembly
{
    public int Id { get; set; }
    public virtual List<SubAssembly> SubAssemblies { get; set; }
}
public class SubAssembly : JobAssembly
{
    public int ParentAssemblyId { get; set; }
    public virtual JobAssembly ParentAssembly { get; set; }
}
public class RootAssembly : JobAssembly
{
    public int JobId { get; set; }
    public virtual Job Job { get; set; }
}
public class Job
{
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual List<RootAssembly> Assemblies { get; set; }
}