我有一个用抽象实体/类构建的EF4模型:
请注意州实体如何具有名为国家/地区的导航属性。
注意:我禁用了延迟加载,因此我必须按需加载。
现在,如果我有以下方法:
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();
}
基本上,我正在做两个相同的电话。它有用吗?是。它漂亮吗?不,而且它并不是真正的“渴望加载”。
我知道这不是正确的解决方案,你们能想到合适的解决方案吗? (是的,我知道我可以使用存储过程,但我真的想在这里浏览我的存储库/模型,因此实体已正确附加到图形,准备编辑)。
即使.Include
导致左外连接,问题是我正在使用“位置”实体集。我需要在{State}上.Include
,但“States”属于“Locations”实体集(派生类属于其父实体集)。
所以我想我的问题实际上是非常通用的 - 我们如何做一个。包含在一个抽象实体的孩子身上,当我们事先不知道孩子是什么时?
请记住,我不能先使用.OfType<T>()
(然后是派生类型的.Include),因为我不知道T是什么(调用代码也不是),因此这里不能使用泛型
答案 0 :(得分:3)
这里真正的问题是你持有Id
,但你不知道它代表什么:它可以是Country
或State
。在某些时候,你可能确实知道它是什么,但你没有保留这些信息。
从存储库加载Location
之后,您如何知道将其强制转换为哪种类型才能访问其中的相关关系属性?大概你必须使用演员as
或is
然后你可以访问这些属性。再次那种气味很糟糕。
这里最好的选择是维护Location对象的Type
和Id
,以便您可以使用适当的存储库方法重新加载它。
另一种选择是将关系移至Location
类,以便每个Location
对象都有.Parent
位置和.Children
位置集合。现在,您可以将它们包含在Include
中,当您发现State
.Parent
时,您知道要查看Country
,当您有.Children
时,您知道要查看context.Locations.OfType<Country>().Include("States").Cast<Location>().Union(context.Locations.OfType<State>().Include("Countries).Cast<Location>());
{1}}。没有父项使用null,没有子项使用空集合。现在,当您将大陆或城市添加到Location类时,您将处于良好的状态以使用相同的模型。
在这种情况下,有时可以使用的最终选项是在将它们转换为公共基类型后将两个查询联合起来,例如:类似的东西: -
{{1}}