3

不久前我问了一个类似的问题:使用数据映射器模式,实体(域对象)是否应该知道映射器?但是,它是通用的,我对如何使用 Doctrine2 专门完成一些事情非常感兴趣

这是一个简单的示例模型:每个都Thing可以有 a Votefrom a User, aUser可以转换多个,Vote但只有最后一个才Vote重要。因为其他数据(Msssage等)与 相关,所以在放置Vote第二个时,原始不能只是更新,它需要替换。VoteVote

目前Thing有这个功能:

public function addVote($vote)
{
  $vote->entity = $this;
}

Vote负责建立关系:

public function setThing(Model_Thing $thing)
{
  $this->thing = $thing;
  $thing->votes[] = $this;
} 

在我看来,确保 a Useronly has last Votecounted 是Thing应该确保的,而不是一些 service layer

因此,为了将其保留在模型中,新Thing功能:

public function addVote($vote)
{
  foreach($this->votes as $v){
    if($v->user === $vote->user){
      //remove vote
    }
  }
  $vote->entity = $this;
}

那么如何Vote从域模型中删除呢?我应该放松Vote::setThing()接受 aNULL吗?我是否应该涉及某种Thing可以用来删除投票的服务层?一旦选票开始累积,那foreach将会很慢 - 是否应该使用服务层来允许Thing搜索 aVote而无需加载整个集合?

我肯定倾向于使用轻量级服务层;但是,有没有更好的方法来使用 Doctrine2 处理这种类型的事情,或者我是否朝着正确的方向前进?

4

2 回答 2

7

我投票支持服务层。我经常努力尝试在实体本身上添加尽可能多的逻辑,只是让自己感到沮丧。如果无法访问 EntityManager,您根本无法执行查询逻辑,并且当您只需要几条记录时,您会发现自己使用大量 O(n) 操作或延迟加载整个关系集(这是超级与 DQL 提供的所有优势相比,这是蹩脚的)。

如果您需要一些帮助来克服贫血域模型始终是反模式的想法,请参阅Matthew Weier O'Phinney 的演示文稿或此问题

虽然我可能会误解术语,但我并不完全相信实体必须是您的域模型中唯一允许的对象。我很容易认为实体对象及其服务的总和构成了模型。我认为当您最终编写一个几乎不关注关注点分离的服务层时,就会出现反模式。

我经常想到让我的所有实体对象代理一些方法到服务层的想法:

public function addVote($vote)
{
   $this->_service->addVoteToThing($vote, $thing);
}

然而,由于 Doctrine 没有任何关于对象水合的回调事件系统,我还没有找到一种优雅的方式来注入服务对象。

于 2010-12-16T21:38:14.477 回答
6

我的建议是将所有查询逻辑放入 EntityRepository 中,然后从中创建一个接口,如下所示:

class BlogPostRepository extends EntityRepository implements IBlogPostRepository {}

这样您就可以在服务对象的单元测试中使用该接口,并且不需要依赖 EntityManager。

于 2010-12-19T21:39:27.870 回答