Используя шаблон сопоставления данных, должны ли сущности (доменные объекты) знать о сопоставителе? - PullRequest
11 голосов
/ 18 сентября 2010

Я работаю с Doctrine2 впервые, но я думаю, что этот вопрос достаточно общий, чтобы не зависеть от конкретного ORM.

Должны ли сущности в шаблоне Data Mapper знать - и использовать - Mapper ?

У меня есть несколько конкретных примеров, но все они, похоже, сводятся к одному и тому же общему вопросу.

Если я имею дело с данными из внешнего источника - например, User имеет много Messages - и внешний источник просто предоставляет последние несколько сущностей (например, канал RSS), как может $user->addMessage($message) проверить для дубликатов, если он либо не знает о Mapper, либо не «ищет» в коллекции (кажется, что это неэффективно).

Конечно, контроллер или сценарий транзакции могут проверять наличие дубликатов перед добавлением сообщения пользователю - но это не совсем правильно и может привести к дублированию кода.

Если у меня большая коллекция - опять же User со многими Messages - как сущность User может обеспечить ограничение и разбиение на страницы для коллекции без фактической передачи вызова Mapper?

Опять же, Контроллер или Сценарий транзакции или все, что использует сущность, может использовать Mapper напрямую для получения коллекции User Messages, ограниченной количеством, диапазоном дат или другими факторами - но это тоже привести к дублированию кода.

Использует ли ответ хранилища и информирует ли их об этом Предприятие ? (По крайней мере, для Doctrine2 и любой аналогичной концепции, используемой другими ORM.) В этот момент сущность все еще относительно отделена от Mapper.

Ответы [ 3 ]

8 голосов
/ 24 сентября 2010

Правило № 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 голос
/ 20 сентября 2010

номер

Вот почему: доверие. Вы не можете доверять данным, чтобы действовать в интересах системы. Вы можете только доверять системе, чтобы действовать на основе данных. Это основа логики программирования.

Допустим, что-то неприятное проскользнуло в данные и предназначалось для XSS. Если блок данных выполняет действия или оценивается, тогда код XSS смешивается с вещами, и это открывает дыру в безопасности.

Пусть левая рука не знает, что делает правая рука! (в основном потому, что ты не хочешь знать)

1 голос
/ 18 сентября 2010

IMO, Сущность должна не забывать, откуда она взялась, кто ее создал и как заполнить связанные с ней Сущности. В ORM, который я использую (свой), я могу определять соединения между двумя таблицами и ограничивать их результаты, указав (в C #):

SearchCriteria sc = new SearchCriteria();
sc.AddSort("Message.CREATED_DATE","DESC");
sc.MaxRows = 10;
results = Mapper.Read(sc, new User(new Message());

Это приведет к объединению, которое ограничено 10 элементами, упорядоченными по дате создания сообщения. Элементы сообщения будут добавлены каждому пользователю. Если я напишу:

results = Mapper.Read(sc, new  Message(new User());

соединение отменено.

Таким образом, можно сделать сущности совершенно не осведомленными о картографе.

...