我已经看过其中的一些问题,但它们似乎总是与我的想法不匹配。 我认为这是由于我对聚合 - 聚合根 - 实体 - 值对象之间关系的粗心理解。
完成的解决方案对我来说就像DTO一样,因为所有(所有逻辑)似乎最终都存储在存储库中。也许我一直在研究EF教程。
假设我们有一个非常简单的类,有一个repo的第一个版本(让我们忽略它只处理一个人):
class Person
{
int Age;
void MakeOlder() { Age++; }
}
interface IPersonRepository
{
Person GetAPerson();
}
现在,我想通过用户界面(例如,按一下按钮)做的是不:
person.MakeOlder();
_repo.Save(person);
但也许只是:
person.MakeOlder();
对我来说,“MakeOlder”的动作是触发保存的动作。但当然这需要在Person中引用repo。 我能想到的唯一选择是:
_repo.MakePersonOlder(person);
(看起来很糟糕。)
person.MakeOlder(_repo);
(UI pov无法获得,这正是我现在所看到的)
class Person : IMyEntityBaseType { ...
void MakeOlder() {
Age++;
EntityDataWasChangedNowIWantToBeSaved();
}
}
或者这个的一些变体;事件,AOP等。以某种方式发信号或捕获应该进行保存。
我想我也可能将我对DDD的观点与事件采购和类似概念混合起来。
我认为UI代码中的SavePerson
调用感觉很脏,我完全错了吗?
“正确”的事情是什么?
答案 0 :(得分:4)
您不应将存储库传递给Person。使用该模型,您必须将存储库传递给每个方法。通常,如果使用EF或其他ORM,则存在unit of work的内置概念。工作单元跟踪在定义的交互中已更改的所有对象。当您提交一个工作单元时,它会提交其中的所有更改。代码看起来更像是:
person.MakeOlder();
_unitOfWork.Commit();
当多个实体发生变化时,可以使用此方法。由于ORM会跟踪更改,因此您无需明确保存属于工作单元的每个对象。
一个更好的选择,也解决了你的问题,是用application service封装用例。应用程序服务将有一个方法,如:
public void MakeOlder(int personId)
{
var person = this.personRepository.Get(personId);
person.MakeOlder();
this.unitOfWork.Commit();
}
然后,UI将直接调用应用程序服务而不是域对象。
答案 1 :(得分:0)
无法达成一致。您缺少ApplicationService概念。应用层非常重要。
我不同意你的意见:
完成的解决方案对我来说就像DTO一样,因为所有(所有逻辑)似乎最终都在>内部存储库。
这是因为你需要更好地理解图层。表示层(UI)将调用na ApplicationService(Façade)。建议的MakePersonOlder(int personId)。
应用层负责协调行动:)
其中一个操作可能会保存到存储库,记录到文本文件,发送电子邮件等等。
疑难杂症?
布鲁诺