【问题标题】:How to implement pagination in DDD?如何在 DDD 中实现分页?
【发布时间】:2013-01-13 23:43:28
【问题描述】:

我有用户和组。每个用户可以有任意数量的组。我想以分页形式显示用户组,一次 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() {
        ...
    }
}

感谢您的帮助!

【问题讨论】:

    标签: php domain-driven-design


    【解决方案1】:

    在 DDD 中,这通常通过直接在存储库上提供分页查询方法来实现。如果一个组严格来说是用户聚合的子实体,那么只需向用户存储库添加一个查询方法。如果一个组是它自己的聚合,则将该方法添加到组存储库。此外,这是一个严格只读的场景,可能专门用于 UI,因此它不是核心域的一部分 - 它更多的是技术问题。

    另一种方法是使用可以注入集合代理的 ORM,该代理在后台对数据库执行命令。这些方法通常比它们的价值更麻烦,并且使域代码更难以推理和维护。

    【讨论】:

      【解决方案2】:

      我对此的看法是根本不查询您的域模型。通过查询您的域,您将立即遇到问题。一旦你意识到你并不总是需要所有的,比如Order 数据,或者你并不总是需要为Order 加载OrderLine 实例,那么你就知道你已经进入了那个雷区:)

      一开始可能看起来很奇怪,但就像您有一个 UserRepository 来获取您的域模型一样,您可以使用 UserQuery 来获取您的读取数据。您可以查看 CQRS(命令/查询职责分离),但从针对您的用例的简单查询开始就足够了。

      您应该很快意识到一些非规范化数据可能会有所帮助,此时您可以开始引入 CQRS。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-02
        • 1970-01-01
        • 2011-02-25
        • 2017-03-07
        • 2021-07-11
        • 2021-11-25
        • 2021-07-26
        相关资源
        最近更新 更多