2014-03-26 48 views
1

我有两个表,一个是自引用这样的:有没有办法自定义实体查询的默认行为?

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,它有一个装配有ID = 1组件1有两个子组件分别是ids = 2和3。当执行var job = db.Jobs.Find(1)时,EF像这样填充对象图:

作业具有全部三个程序集(因为jobid在所有三个== 1上)。具有ID 1的JobAssembly使其子部件适当地填充。

所有这些都是预期的,但如果我可以定制EF如何加载对象,那将会很好。作业不应该具有JobId == 1的每个JobAssembly,但只有JobId == 1和ParentAssemblyId == null的地方。

+0

你能显示代码?没有'虚拟'关键字,因此不会延迟加载。所以你必须急于加载它,否则你不会得到任何程序集所有的程序集 – Colin

+0

我的错。让我显示虚拟关键字。我将编辑。 –

+0

你想引入“只是父母” - 即树的根。或者你想引入“JobAssemblies没有子装配” - 即叶子? – Colin

回答

2

如果我理解正确,您希望Job.Assemblies仅包含那些没有父项的组件(即那些作业是直接子项的组件,而不是孙子项等)。

做到这一点的“正常”方式是只让直接孩子通过外键参考工作,让孙子们等参考他们的父母。

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

有几种方法可以让你获得工作的直接子女。最简单的方法是只有你的工作类的属性做过滤为您提供: -

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将您的查询投影到您的视图模型上。

0

下面是使用继承RootAssemblies和组件之间进行区分的想法:在这里你填充`Assemblies`财产

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; } 
} 
相关问题