据我所知,您的问题源于您有一个由 DTO 制成的本地明确声明的对象图。我的意思是你已经public Unit Unit { get; set; }
在你的Country
模型上声明了(不知道你为什么要声明它们virtual
,但这与手头的问题没有直接关系),而不是尝试一种方法来保证对象图的简单性变成单一的退化情况对象图节点。
例如,考虑以实际可能存在的形式或用于唯一标识和区分的任何形式定义模型上的每个“引用”属性public UnitID Unit { get; set; }
UnitID
int
Guid
Unit
彼此的模型。无论您在哪里有对另一个模型的引用或一组引用,都将其替换为其标识符类型而不是其实际类型。这种策略很适合一组持久化的模型,例如从/到每个模型都有身份密钥的数据库。这样做可以让您简化序列化,而不必担心循环引用,因为它们现在是不可能的。从技术上讲,不再有引用(即直接引用;它们现在是间接引用)。我们现在只是在您的域模型设计中添加一个间接层。现在让我们适应那个间接层。
既然你声称你对贫血域模型方法没问题,那么这应该很适合。您在模型设计中支付次要(恕我直言)间接成本,并将其换成基于接口的数据检索方法的主要(恕我直言)好处:
public interface IUnitRepository {
Unit GetUnit(UnitID id);
IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
// etc.
}
在您的消费者代码(即使用此接口和您的Unit
域模型的代码)中,通过执行接口调用以获取间接引用指向的基础模型,遍历隐含对象图看起来稍微复杂一些。
前:
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit;
后:
// 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)
方法的实现是天真的。此方法现在可以使用Dictionary<UnitID, Unit>
与SomeUnitsRepositoryImpl
.
有点啰嗦,但希望对你有帮助。好像从所提供的细节数量上看不明显,我目前正在我的工作地点玩弄这种设计,以处理我们的记录数据库系统。:) 我真的很喜欢它给我的所有灵活性,而代价是在域模型的设计中添加一层间接性。