我是第一次使用Doctrine2,但我认为这个问题非常通用,不依赖于特定的ORM。
数据映射器模式中的实体是否应该知道 - 和 使用 - Mapper?
我有几个具体的例子,但它们似乎都归结为同样的一般性问题。
如果我正在处理来自外部源的数据 - 例如a User 有很多 Messages - 外部源只提供最新的几个实体(如RSS提要),怎么可以 $user->addMessage($message) 检查重复项,除非它知道Mapper,或者“搜索”整个集合(看起来像一个低效的事情)。
当然,控制器或事务脚本可以在将消息添加到用户之前检查重复项 - 但这似乎不太正确,并且会导致代码重复。
如果我有一个大集合 - 再来一个 User 与许多 Messages - 怎么可能 User 实体为集合提供限制和分页而不实际代理Mapper调用?
同样,Controller或Transaction Script或使用Entity的任何东西都可以直接使用Mapper来检索它的集合 User的 Messages 受到计数,日期范围或其他因素的限制 - 但这也会导致代码重复。
答案是使用存储库并使实体了解它们? (至少对于Doctrine2,以及其他ORM使用的类似概念。)此时,实体仍然与Mapper相对分离。
规则#1:保持您的域模型简单明了。
首先,不要过早地优化某些东西,因为你认为它可能效率低下。构建域以使对象和语法正确流动。保持接口干净:$ user-> addMessage($ message)干净,精确且明确。在引擎盖下,您可以使用任意数量的模式/技术来确保维护完整性(缓存,查找等)。您可以利用服务来协调(复杂)对象依赖,这可能是过度的,但这是一个基本的示例/想法。
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);
一直在使用Doctrine2。您的域实体对象就是那些对象......他们不应该知道它们来自何处,域模型只管理它们并将它们传递给管理和操作它们的各种函数。
回顾过去,我不确定我是否完全回答了你的问题。但是,我不认为实体本身应该可以访问映射器。创建服务/存储库/无论在对象上操作什么,并在这些功能中使用适当的技术......
从发病开始也不要过度工程化。当性能实际上是一个问题时,让您的域名专注于其目标和重构。
规则#1:保持您的域模型简单明了。
首先,不要过早地优化某些东西,因为你认为它可能效率低下。构建域以使对象和语法正确流动。保持接口干净:$ user-> addMessage($ message)干净,精确且明确。在引擎盖下,您可以使用任意数量的模式/技术来确保维护完整性(缓存,查找等)。您可以利用服务来协调(复杂)对象依赖,这可能是过度的,但这是一个基本的示例/想法。
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 *%