4

我有一个用抽象实体/类构建的 EF4 模型:

替代文字

请注意State实体如何具有名为Country的导航属性。

注意:我禁用了延迟加载,所以我必须按需加载。

现在,如果我有以下方法:

public Location FindSingle(int id)
{
   return _repository.Find().WithId(id).SingleOrDefault();
}

默认情况下,这不会返回任何关联。但是,当我明确想要时,如何动态地预先加载关联?

我不能做到这一点:

return _repository.Find().WithId(id).Include("Country").SingleOrDefault();

因为我正在使用一个名为Location的抽象类,它没有名为“Country”的导航属性。在我实际执行查询之前,我不知道.SingleOrDefault派生类型是什么。

所以,这就是我必须做的:

public Location FindSingle(int id, bool includeAssociations = false)
{
    var location = _repository.Find().WithId(id).SingleOrDefault();
    return includeAssociations
                       ? LoadAssociation(location)
                       : location;
}

private Location LoadAssociation(Location location)
{
   // test derived-type, e.g:
   var state = location as State;

   if (state != null) 
      return _repository.Find().OfType<State>().Include("Country").WithId(id).SingleOrDefault();
}

本质上,我正在做 2 个相同的电话。它有效吗?是的。漂亮吗?不,这并不是真正的“急切加载”。

我知道这不是正确的解决方案,你们能想到正确的解决方案吗?(是的,我知道我可以使用存储过程,但我真的很想在这里查看我的存储库/模型,以便实体正确地附加到图表上,准备好进行编辑)。

即使.Include导致左外连接,问题是我正在处理“位置”实体集。我需要.Include在“状态”上,但“状态”属于“位置”实体集(派生类属于其父实体集)。

所以我想我的问题实际上很笼统——当我们事先不知道孩子是什么时,我们如何在抽象实体的孩子上做一个 .Include ?

请记住,我不能.OfType<T>()先使用(然后是派生类型上的 .Include),因为我不知道 T 是什么(调用代码也不知道),因此这里不能使用泛型。

4

1 回答 1

3

这里真正的问题是你拿着 anId但你不知道它代表什么:它可能是 aCountry或 a State。有时您可能确实知道它是什么,但您没有保留该信息。

从存储库加载 a 后Location,您如何知道将其转换为哪种类型以便访问其上的相关关系属性?大概你必须使用asor iswith cast 然后你可以访问这些属性。再一次闻起来有点难闻。

这里最好的选择是同时维护Location 对象的Type和 ,以便您可以使用适当的存储库方法重新加载它。Id

另一种选择是将关系向上移动到Location类,以便每个Location对象都有一个.ParentLocation 和一个.ChildrenLocations 集合。现在您可以将它们包含在您的 中Include,当您发现您有一个State您知道要查看时,.Parent以及当您有一个Country您知道要查看时.Children。使用 null 表示没有父级,使用空集合表示没有子级。现在,当您将大陆或城市添加到 Location 类中时,您将可以很好地使用相同的模型。

您有时可以在这种情况下使用的最后一个选项是在将两个查询转换为通用基本类型后合并两个查询,例如:-

context.Locations.OfType<Country>().Include("States").Cast<Location>().Union(context.Locations.OfType<State>().Include("Countries).Cast<Location>());
于 2010-10-25T03:40:51.130 回答