C# 有没有办法自定义实体查询的默认行为?

C# 有没有办法自定义实体查询的默认行为?,c#,entity-framework,C#,Entity Framework,我有两个表,其中一个是自引用,如下所示: 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

我有两个表,其中一个是自引用,如下所示:

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只引入没有子部件的JobAssembly。。。作为默认行为?我知道如何查询所述父程序集的EF。但是,有没有一种方法可以设置映射,或者以其他方式设置默认查询行为,以便只获取parentassemblyid==null的程序集

谢谢:)

编辑:

请允许我举例说明:

我有一份id为1的工作。它有一个id为1的程序集。部件1有两个子部件,其ID分别为2和3。当执行var job=db.Jobs.Find(1)时,EF填充对象图,如下所示:

作业具有所有三个程序集(因为所有三个程序集上的jobid==1)。id为1的JobAssembly已正确填充其子部件


所有这些都是意料之中的,但如果我可以自定义EF加载对象的方式,那就太好了。作业不应具有JobId==1的所有JobAssembly,而应仅具有JobId==1和ParentAssemblyId==null的JobAssembly

如果我理解正确,您希望Job.Assemblies只包含那些没有父级的程序集(即,那些是作业的直接子级的程序集,而不是子级的程序集等)

这样做的“正常”方式是只让直系子女通过外键引用工作,而让孙辈等仅引用他们的父母

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

有几种方法可以让你只得到工作中的直系子女。最简单的方法是让作业类的属性为您进行筛选:-

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);
    }
  }
}
公共类作业
{
公共int Id{get;set;}
公共字符串说明{get;set;}
公共虚拟列表程序集{get;set;}
公共数字儿童
{
得到
{
返回此值。程序集==null
无效的
:this.Assemblies.Where(x=>x.ParentAssemblyId==null);
}
}
}
但是如果你要采取这种方法,你需要这样做。有些人在遇到问题时会想“我知道,我会使用O/RM”。现在他们有N+1个问题;)

一个更健壮的解决方案是使用一个单独的ViewModel来封装应用层中所需的树结构。这可以防止选择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; }
}
公共类JobViewModel
{
公共int Id{get;set;}
公共字符串说明{get;set;}
公共虚拟列表子项{get;set;}
}
公共类JobAssemblyViewModel
{
公共int Id{get;set;}
公共虚拟列表子项{get;set;}
}

如果你这么做,你可能想考虑使用例如AutoPAPER来为你的视图模型设计你的查询。

< P>这是一个使用继承来区分根组件和子组件的想法:

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; }
}
公共抽象类JobAssembly
{
公共int Id{get;set;}
公共虚拟列表子部件{get;set;}
}
公共类子部件:JobAssembly
{
public int ParentAssemblyId{get;set;}
公共虚拟作业程序集父程序集{get;set;}
}
公共类根程序集:JobAssembly
{
public int JobId{get;set;}
公共虚拟作业作业{get;set;}
}
公开课工作
{
公共int Id{get;set;}
公共字符串说明{get;set;}
公共虚拟列表程序集{get;set;}
}

能否显示填充
程序集
属性的代码?没有
virtual
关键字,因此不会延迟加载。因此,您必须以某种方式加载它,否则您将无法获得任何程序集,更不用说所有的程序集了。让我显示虚拟关键字。我将进行编辑。你想引入“仅仅是父母”——即树的根吗。或者您想引入“没有子部件的JobAssembly”-即叶子?我需要整个树,但有一些自定义限制。我在上面的编辑中解释得更详细。
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; }
}