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

时间:2014-03-26 18:37:31

标签: 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 { 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表示所述父程序集。但是有没有办法设置映射,或者其他方式,将默认查询行为设置为仅获取其父组件== null的程序集?

谢谢:)

编辑:

请允许我说明一下:

我有一个id为1的Job。它有一个id = 1的汇编。汇编1有两个子汇编,其中id分别为2和3。执行var job = db.Jobs.Find(1)时,EF会填充对象图,如下所示:

作业有三个程序集(因为所有三个程序都是= = 1)。 id为1的JobAssembly已正确填充其子装配。

所有这一切都是预料之中的,但如果我可以自定义EF加载对象的方式会很好。 Job不应该在JobId == 1的每个JobAssembly中,而只在JobId == 1和ParentAssemblyId == null的地方。

2 个答案:

答案 0 :(得分:2)

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

这样做的“正常”方式是让直接的孩子通过外键引用Job,让孙子等只引用他们的父母。

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

有几种方法可以只获得工作的直接子女。最简单的方法是让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);
    }
  }
}

但如果您打算采用这种方法,则需要really really careful that you're not lazy loading data in a silly way。有些人在遇到问题时会想“我知道,我会使用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; }
}

如果您经常这样做,您可能需要考虑使用例如AutoMapper可以将查询投射到您的视图模型上。

答案 1 :(得分:0)

这是一个使用继承来区分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; }
}
相关问题