4

ユーザーとグループがあります。各ユーザーは、任意の数のグループを持つことができます。ユーザーグループをページ化された形式で、一度に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() {
        ...
    }
}

ご協力ありがとうございました!

4

2 に答える 2

7

DDDでは、これは通常、ページ付けされたクエリメソッドをリポジトリに直接提供することによって実装されます。グループが厳密にUserアグリゲートの子エンティティである場合は、クエリメソッドをユーザーリポジトリに追加するだけです。グループがそれ自体の集合体である場合は、そのメソッドをグループリポジトリに追加します。また、これは厳密に読み取り専用のシナリオであり、おそらく排他的にUIに使用されるため、コアドメインの一部ではありません。これは、技術的な問題です。

別の方法は、バックグラウンドでデータベースに対してコマンドを実行するコレクションプロキシを挿入できるORMを使用することです。これらのアプローチは通常、価値があるよりも厄介であり、ドメインコードの推論と維持をより困難にします。

于 2013-01-14T00:07:32.420 に答える
4

これについての私の見解は、単にドメインモデルをクエリしないことです。ドメインにクエリを実行すると、すぐに問題が発生します。たとえば、すべてのデータが常に必要であるとは限らないこと、またはインスタンスをOrder常にロードする必要がないことに気付いたら、その地雷原に入ったことがわかります:)OrderLineOrder

UserRepository最初は奇妙に思えるかもしれませんが、ドメインモデルにアクセスするための情報があるのと同じようUserQueryに、読み取りデータにアクセスする必要があります。CQRS(Command / Query Responsibility Segregation)を見ることができますが、ユースケースに向けられた単純なクエリから始めるだけで十分です。

一部の非正規化データが、CQRSの導入を開始できる時点で役立つ可能性があることをすぐに理解する必要があります。

于 2013-01-14T04:58:36.440 に答える