我有两个表,一个是这样的自引用:
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的地方。
答案 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; }
}