我有用户和群组。每个用户可以拥有任意数量的组。我希望以分页形式显示用户组,一次显示n个组。我知道如何实现普通的分页,但我不知道如何将它集成到我的域驱动设计(并且不会导致代码重复)。我希望它能像这样工作:
$adapter = new DatabaseAdapter(...);
$userRepository = new UserRepository($adapter);
$user = $userRepository->fetchById(1);
$groups = $user->getGroups()->getRange($offset, $limit);
和其他域实体相同:
$projects = $user->getProjects()->getRange($offset, $limit);
...
简化,我的代码如下:
class Group
{
private $_id;
private $_name;
public function __construct($id, $name) {
$this->setId($id);
$this->setName($name);
}
public function setId() {
$this->_id = $id;
}
public function getId() {
return $this->_id;
}
public function setName($name) {
$this->_name = $name
}
public function getName() {
return $this->_name;
}
}
class Groups
{
private $_elements = array();
public function __construct(array $groups) {
foreach($groups as $group) {
if(!($group instanceof Group)) {
throw new Exception();
}
$this->_elements[] = $group;
}
}
public function toArray() {
return $this->_elements;
}
}
class GroupMapper
{
private $_adapter;
public function __construct(DatabaseAdapterInterface $adapter) {
$this->_adapter = adapter;
}
public function fetchById($id) {
$row = $this->_adapter->select(...)->fetch();
return $this->createEntity($row);
}
public function fetchAll() {
$rows = $this->_adapter->select(...)->fetchAll();
return $this->createEntityCollection($rows);
}
private function createEntityCollection(array $rows) {
$collection = array();
foreach($rows as $row) {
$collection[] = $this->createEntity($row);
}
return $collection;
}
private function createEntity(array $row) {
return new Group($row['id'], $row['name']);
}
}
class User
{
private $_id;
private $_name;
private $_groups;
public function getId() {
return $this->_id;
}
public function setName($name) {
$this->_name = $name;
}
public function getName() {
return $this->_name;
}
public function setGroups($groups) {
$this->_groups = $groups;
}
public function getGroups() {
return $this->_grous;
}
}
class UserRepository
{
private $_userMapper = null;
private $_groupMapper = null;
public function __construct(DatabaseAdapterInterface $adapter) {
$this->_groupMapper = new GroupMapper($adapter);
$this->_userMapper = new UserMapper($adapter);
}
public function fetchById($id) {
$user = $this->_userMapper->fetchById($id);
if($user) {
$groups = $this->_groupMapper->fetchAllByUser($id);
$user->setGroups($groups);
}
}
public function fetchAll() {
...
}
}
感谢您的帮助!
答案 0 :(得分:7)
在DDD中,这通常通过直接在存储库上提供分页查询方法来实现。如果组严格地是User聚合的子实体,则只需将查询方法添加到用户存储库。如果组是其自己的聚合,请将该方法添加到组存储库。此外,这是一个严格的只读方案,可能仅用于UI,因此它不是核心域的一部分 - 这更多是技术问题。
替代方法是使用可以注入集合代理的ORM,该代理在后台对数据库执行命令。这些方法通常比它们的价值更麻烦,并使域代码更难以推理和维护。
答案 1 :(得分:4)
我对此的看法是不查询您的域模型。通过查询您的域名,您将立即遇到问题。一旦你意识到你并不总是需要所有的Order
数据,或者你并不总是需要为OrderLine
加载Order
个实例,那么你就知道你已进入那个雷区:)
起初看起来可能很奇怪,但正如您有UserRepository
来获取您的域模型一样,您可以UserQuery
来获取您的读取数据。您可以查看CQRS(命令/查询责任隔离),但从针对您的用例的简单查询开始就足够了。
您应该很快意识到,一些非规范化数据可以帮助您在何时开始引入CQRS。