使用数据映射器模式,实体(域对象)是否知道映射器? [英] Using the Data Mapper Pattern, Should the Entities (Domain Objects) know about the Mapper?

查看:120
本文介绍了使用数据映射器模式,实体(域对象)是否知道映射器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我第一次和Doctrine2一起工作,但我认为这个问题是通用的,不能依赖于一个特定的ORM。



应该知道Data Mapper模式中的实体 - 并且使用 - Mapper



我有一些具体的例子,但他们似乎都归结为同样的一般问题。



如果我正在处理来自外部来源的数据,例如用户有很多消息 - 外部源只提供最新的几个实体(如RSS提要),如何 $ user-> addMessage($ message)检查重复项,除非它知道Mapper,或者通过集合搜索(看起来像是无效的事情)。



当然控制器或事务脚本可以在向用户添加消息之前检查重复项,但这似乎不太正确,并且会导致代码重复。



如果我有一个大集合 - 再次是一个用户与许多消息 - 如何可以用户实体为集合提供限制和分页,而不实际代理Mapper调用?



再次,控制器或事务脚本或者使用实体的任何内容都可以使用Mapper直接检索ac 用户消息受到计数,日期范围或其他因素的限制,但也会导致代码重复。



使用存储库的答案是否使实体意识到? (至少对于Doctrine2,以及其他ORM使用的任何类似的概念)。在这一点上,实体仍然与Mapper相对脱钩。

解决方案

规则#1:使您的域模型简单直观。



首先,不要过早优化某些内容,因为您认为这可能无效率。构建您的域,使对象和语法流正确。保持接口清洁:$ user-> addMessage($ message)是干净,精确和明确的。在引擎盖下,您可以使用任何数量的模式/技术来确保完整性得到维护(缓存,查找等)。您可以使用服务来编排(复杂的)对象依赖关系,这可能是过度的,但这里是一个基本的示例/想法。

  class用户
{
public function addMessage(Message $ message)
{
//一个解决方案,首先循环遍历所有消息,抛出错误如果已经存在
$ this- > messages [] $ message;
}
public function getMessage()
{
return $ this-> messages;
}
}
class MessageService
{
public function addUserMessage(User $ user,Message $ message)
{
//确保唯一消息给用户
//一个解决方案是循环通过$ user-> getMessages()在这里,并确保唯一
//这或多或少是添加消息的唯一路径,因此确保其完整性在此之前
//还可以在此处放置ACL检查
//您还可以创建提供检查的函数,以确定在执行
之前某些条件是否满足/未满足if( $ this-> doesUserHaveMessage($ user,$ message)){
throw异常...
}
$ user-> addMessage($ message);
}
//注意,这可能不是这个函数活的正确位置
public function doesUserHaveMessage(User $ user,Message $ message)
{
//在这里执行数据库查找
return($ user-> hasMessage($ message)?true
}
}
class MessageRepository
{
public function find(/ * criteria * /)
{
//在这里使用缓存
return $ message;
}
}

class MessageFactory
{
public function createMessage($ data)
{
//
$ message = new Message();
// setters
return $ message;
}
}

//应用程序代码
$ user = $ userRepository-> find(/ * lookup criteria * / );
$ message = $ messageFactory-> create(/ * data * /);
//可以包装try / catch
$ messageService-> sendUserMessage($ user,$消息);

与Doctrine2一起使用您的域实体对象只是对象...他们不应该知道他们来自哪里,域模型只是管理它们,并将它们传递给管理和操纵它们的各种功能。



<回头看,我不知道我完全回答了你的问题。但是,我不认为实体本身应该可以访问映射器。创建服务/存储库/无论对对象进行操作,并在这些功能中使用适当的技术。



不要从开始开始。保持您的域名专注于其目标,并在性能实际上是一个问题时重构。


I'm working with Doctrine2 for the first time, but I think this question is generic enough to not be dependent on a specific ORM.

Should the entities in a Data Mapper pattern be aware - and use - the Mapper?

I have a few specific examples, but they all seem to boil down to the same general question.

If I'm dealing with data from an external source - for example a User has many Messages - and the external source simply provides the latest few entities (like an RSS feed), how can $user->addMessage($message) check for duplicates unless it either is aware of the Mapper, or it 'searches' through the collection (seems like an inefficient thing to do).

Of course a Controller or Transaction Script could check for duplicates before adding the message to the user - but that doesn't seem quite right, and would lead to code duplication.

If I have a large collection - again a User with many Messages - how can the User entity provide limiting and pagination for the collection without actually proxying a Mapper call?

Again, the Controller or Transaction Script or whatever is using the Entity could use the Mapper directly to retrieve a collection of the User's Messages limited by count, date range, or other factors - but that too would lead to code duplication.

Is the answer using Repositories and making the Entity aware of them? (At least for Doctrine2, and whatever analogous concept is used by other ORMs.) At that point the Entity is still relatively decoupled from the Mapper.

解决方案

Rule #1: Keep your domain model simple and straightforward.

First, don't prematurely optimize something because you think it may be inefficient. Build your domain so that the objects and syntax flow correctly. Keep the interfaces clean: $user->addMessage($message) is clean, precise and unambiguous. Underneath the hood you can utilize any number of patterns/techniques to ensure that integrity is maintained (caching, lookups, etc). You can utilize Services to orchestrate (complex) object dependencies, probably overkill for this but here is a basic sample/idea.

class User
{
  public function addMessage(Message $message)
  {
     // One solution, loop through all messages first, throw error if already exists
     $this->messages[] $message;
  }
  public function getMessage()
  {
     return $this->messages;
  }
}
class MessageService
{
  public function addUserMessage(User $user, Message $message)
  {
     // Ensure unique message for user
     // One solution is loop through $user->getMessages() here and make sure unique
     // This is more or less the only path to adding a message, so ensure its integrity here before proceeding 
     // There could also be ACL checks placed here as well
     // You could also create functions that provide checks to determine whether certain criteria are met/unmet before proceeding
     if ($this->doesUserHaveMessage($user,$message)) {
       throw Exception...
     }
     $user->addMessage($message);
  }
  // Note, this may not be the correct place for this function to "live"
  public function doesUserHaveMessage(User $user, Message $message)
  {
     // Do a database lookup here
     return ($user->hasMessage($message) ? true
  }
}
class MessageRepository
{
  public function find(/* criteria */)
  {
     // Use caching here
     return $message;
  }
}

class MessageFactory
{
   public function createMessage($data)
   {
     //
     $message = new Message();
     // setters
     return $message;
   }
}

// Application code
$user = $userRepository->find(/* lookup criteria */);
$message = $messageFactory->create(/* data */);
// Could wrap in try/catch
$messageService->sendUserMessage($user,$message);

Been working with Doctrine2 as well. Your domain entity objects are just that objects...they should not have any idea of where they came from, the domain model just manages them and passes them around to the various functions that manage and manipulate them.

Looking back over, I'm not sure that I completely answered your question. However, I don't think that the entities themselves should have any access to the mappers. Create Services/Repositories/Whatever to operate on the objects and utilize the appropriate techniques in those functions...

Don't overengineer it from the onset either. Keep your domain focused on its goal and refactor when performance is actually an issue.

这篇关于使用数据映射器模式,实体(域对象)是否知道映射器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆