从我所能理解的,你的问题源于你有一个由你的DTO制作的本地显式声明的对象图的事实。我的意思是你已经在你的Country
模型上声明public Unit Unit { get; set; }
(不知道你为什么声明它们是virtual
,但这与手头的问题没有直接关系),而不是尝试一种方法来保证对象图简化为简并案例的单个对象图节点。
例如,考虑形式public UnitID Unit { get; set; }
定义每“参照”财产上的模型,其中UnitID
实际上可能int
或Guid
或者你用它来相互唯一识别和区分Unit
模型。只要你有一个引用或一组引用另一个模型,用它的标识符类型而不是它的实际类型替换它。这种策略适用于一套持久的模型,例如从/到每个模型具有身份密钥的数据库。这样做可以让你简单的序列化,而不必担心循环引用,因为它们现在是不可能的。从技术上讲,没有更多的引用(即直接引用;它们现在是间接引用)。我们现在只是在您的领域模型设计中添加一个间接层。现在我们来适应那个间接层。
既然你声称你对贫血域模型方法很好,那么这应该与此相适应。你付出的间接的未成年人(恕我直言)成本模型的设计和交易它的主要(恕我直言)基于接口的方法的好处数据检索:
public interface IUnitRepository {
Unit GetUnit(UnitID id);
IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
// etc.
}
在你的消费者的代码(即代码使用此接口和域模型),通过执行接口调用以获取由间接引用指向的基础模型来遍历隐含对象图只会稍微复杂一些。
BEFORE:
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit;
AFTER:
// Somewhere earlier in your code, i.e. not *every* time this type of code appears
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = repo.GetUnit(ct.UnitID);
如果这句法困扰你,你可以定义上键入形式的Country
一套扩展的方法:
public static Unit Unit(this Country c, IUnitsRepository repo) {
return repo.GetUnit(c.UnitID);
}
扩展方法后:
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit(repo);
基于接口的方法可以为您带来经典的一系列优点,如关注点分离,可测试性,消费者与生产者绝缘等等。此外,您现在可以通过接口的实现类型更直接地控制对象的生命周期。我的意思是,你不应该假设你的Unit GetUnit(UnitID id)
方法的实施是天真的。此方法现在可以使用与SomeUnitsRepositoryImpl
的实例绑定的Dictionary<UnitID, Unit>
执行一些本地内存缓存。
有点啰嗦,但我希望它有帮助。仿佛从提供的细节数量来看,这并不明显,我目前正在我的工作地点开展这项设计,以处理我们的记录数据库系统。 :)我真的非常喜欢它给我所有的灵活性,只需在域模型的设计中增加一层间接寻址的简单代价。
好吧,所以属性是虚拟的原因是因为我正在使用和ORM(NHibernate在这种情况下),它需要我的POCO国家对象,并围绕它建立一个代理来自动挂钩延迟加载相关对象(即单位这个案例)。现在,我可以让Country对象与您声明的任何其他模型没有关系,但这意味着要手动创建所有这些管道工作。这对我来说不是一个好的折衷,因为我认为序列化程序应该足够灵活,可以让我采用复杂的模型,只显示我选择的内容。我最终选择了AutoMapper – Owen 2009-12-21 23:06:25