这里的问题是关于如何正确处理DDD DE,假设我们有这个非常简单的例子(我知道对于简单的项目,不需要DDD,但这只是一个例子)。我们有User(Aggregate root)和UserProfile(Value Object),所以表是:
用户
- id
- email
- password
user_profile
- country_id
- first_name
- second_name
我们知道我们的代码应该表达行为并且不应该以数据为中心,所以例如在我们的六边形(UI浏览器)之一,我们有这个应用程序服务来处理情况:
//UserService application service
public static function update($formDTO)
$user->changeCountry($form->country);
$user->changePassword($form->password);
$user->attributes = $form->userData();
$user->save(); // here we use AR not DDD ORM like; you can see this as entityManager->flush(); if you like Hibernate or Doctrine.
方法changeCountry
看起来像:
public function changeCountry($country)
{
if ($this->country->id != $country->id) {
$oldCountry = $this->country;
$this->moveToCountry($country);
...->eventsManager->raise(new UserMovedToCountryEvent(
[
'user' => $this,
'oldCountry' => $oldCountry,
'newCountry' => $newCountry,
],
))
}
}
有关changePassword
和changeCountry
方法的问题:
save
中致电$user->changeCountry()
吗?此类行为方法(changePassword
和changeCountry
)在更改后是否会将对象保留在存储中?changeCountry
或moveToCountry
)用于表达行为但是应该启动事务吗?这个是否有任何推荐?UserProfileChanged
$oldInfo
之类的参数来发起一个域名事件$newInfo
,但对于我而言,这个事件缺少域名。重点是使事情正确,但没有不必要的持久性调用。我知道我不应该考虑域层的持久性,但是获取20
sql更新而不是1
并不是一个好的解决方案。
答案 0 :(得分:0)
域对象不应该关注持久性。 Repositories
负责聚合持久性。您将从存储库中获取聚合,调用聚合上的方法并在应用程序层中再次保留它。这导致两个数据库调用;一个SELECT和一个UPDATE - 在一个事务中汇总。
var user = repository.GetById(userId);
user.MoveToCountry(country);
repository.Update(user);
我知道这只是一个例子,但请确保捕获用户的意图。这种更新方法看起来像是在构建一个CRUD应用程序,但是在事实发生后正试图对意图进行逆向工程 - 这在你重构等时可能有意义。