Data Mapper вопрос в C # .NET - PullRequest
       44

Data Mapper вопрос в C # .NET

3 голосов
/ 15 февраля 2011

Кажется, что вокруг DDD, репозиториев, средств отображения данных и т. Д. Происходит много "шума", и очень мало кода реализации "реального мира", чтобы показать новичкам, таким как я, что "хорошо", а что "плохо".

Я только что закончил читать книгу Архитектура приложений для предприятия , и это стало большим откровением. В настоящее время я использую шаблон Active Record для проекта на работе и работаю над его изменением для использования модели предметной области. Я использовал множество примеров архитектуры в книге, а также загрузку кода из набора для начинающих Northwind, которая является дополнением к книге.

Все шло отлично, но теперь я столкнулся с моей первой проблемой отображения данных в "реальном мире" ... иначе, вместо того, чтобы мой редактор просто отвечал за то, что взял один объект Entity и сохранил его в базе данных, я теперь иметь объект Entity, имеющий коллекцию IList <>, которую также необходимо отобразить.

Основным объектом Entity является Expert, вот код:

   public class Expert
   {    
          public int ID { get; set; }
          public string FirstName { get; set; }
          public string LastName { get; set; }
          public virtual IList<Case> Cases { get; protected set; }
   }

Вот реализация коллекции из Expert, объекта Case:

   public class Case
   {
          public int ID { get; set; }
          public string Name { get; set; }
   }

Не может быть намного проще, чем это.

Теперь у меня есть DataMapper для каждого элемента сущности, но мой вопрос заключается в том, что когда я иду сопоставить коллекцию Case в моем коде ExpertDataMapper, что считается «правильным» способом сделать это?

В книге приведен фактический код SQL, который встроен в ExpertDataMapper, который обращается к коду ADO.NET, который принимает все элементы Case в коллекции IList и вызывает этот код один раз для каждого элемента. Вот некоторый псевдокод:

   public virtual void Create(Expert expert)
   {
          // Insert expert in the Expert table
          SqlHelper.ExecuteNonQuery(ProviderHelper.ConnectionString, CommandType.Text,
          "SQL TO INSERT EXPERT", this.BuildParamsFromEntity(expert));

          // Insert individual Case items in the Case table
          foreach (Case c in expert.Cases)
          {
                 SqlHelper.ExecuteNonQuery(ProviderHelper.ConnectionString, CommandType.Text,
                 "SQL TO INSERT CASE", this.BuildParamsFromEntity(order));
          }
    }

Итак, две вещи не так сразу бросаются в меня:

  1. Почему ExpertDataMapper имеет вызов SQL (или хранимый вызов proc) для вставки встроенного в себя Case? Для меня это нарушает идею инкапсуляции ... ExpertDataMapper не должен ничего знать о том, как Case вставляется в базу данных, то есть работа CaseDataMapper.

Я бы предположил, что ExpertDatMapper ДОЛЖЕН ДЕЛЕГИРОВАТЬ задачу вставки Case в CaseDataMapper ... но я не знаю, является ли это "правильным" или "неправильным" для одного DataMapper для создания экземпляра другого. Это считается обычной проблемой с DataMappers? Я не могу найти никаких указаний по этой проблеме, которые, как я полагаю, довольно распространены.

  1. Если у меня есть 100 дел, связанных с этим экспертом, это 100 созданных объектов дел и 100 операторов вставки для базы данных? Что-то в этом мне кажется «неправильным» и противоречит моему лучшему суждению. Теперь, если бы мне посчастливилось использовать SQL Server 2008, я мог бы использовать Table Valued Parameters, и это было бы не так плохо, но сейчас у нас 2005 год.

Итак, когда дело доходит до DataMappers, я не видел никаких конкретных реализаций простого создания, обновления и т. Д. В DataMaper объекта сущности с простой ассоциацией коллекции. В книге, которую я читаю, нет кода для ее поддержки (и код, который там находится, кажется мне подозрительным).

Я прочитал и владею книгой Мартина Фаулера о EAA, поэтому, пожалуйста, не говорите мне искать там. Я также знаю о доступных мне инструментах ORM, поэтому мне не нужно заботиться о реализации DAL самостоятельно. Я играл с EF 4.0, и мне это нравится. Но для этого проекта у меня нет возможности использовать инструмент ORM.

Большинство книг / примеров, кажется, останавливаются на одной и той же базовой предпосылке, что, пока у меня есть однозначная связь между моим объектом Entity и таблицей, к которой он сохраняется с помощью DataMapper, мир просто окрашен в розовый цвет используя подход Доменная модель ...

Если бы все мои сущности были один-на-один, я мог бы просто использовать Active Record и покончить с этим.

Любое руководство, предложения, понимание? Извините, это длинный пост, но я читал другие посты с похожими проблемами, и никаких конкретных ответов или предложений о том, как решить проблему, представленных здесь, нет.

Ответы [ 2 ]

4 голосов
/ 15 февраля 2011

По первому пункту вы правы, с точки зрения «ТВЕРДЫХ». Вместо того, чтобы обрабатывать само постоянство, было бы более легко поддерживать и менее избыточно реализовывать CaseDataMapper, который используется ExpertDataMapper. Это, вероятно, не было сделано по нескольким причинам, главным образом связанным с простотой. Если у вас есть отдельный класс, который должен работать в одной и той же транзакции, вы должны передать транзакцию. Само по себе это не страшно, но оно порождает больше вопросов о том, как сделать реализацию архитектуры независимой. Если вы просто передадите транзакцию, вы подключитесь к обычному ADO.NET и не сможете позже перейти на ORM, такой как MSEF, NHibernate, Linq2SQL и т. Д. Поэтому вам нужен шаблон UnitOfWork, который позволяет скрыть фактическую Транзакция или Сеанс или DataContext или что-либо еще в Репозитории. К настоящему времени этот относительно простой фрагмент кода теперь представляет собой два полных определения классов с большим количеством материала.

Чтобы избежать всего этого в целях иллюстрации одного эксперта, они просто помещают код для сохранения дел в эксперта. Это в основном делает предположение, что Case всегда будет ссылаться как дочерний элемент эксперта, и поэтому не стоило бы разделять функциональность на что-то, что можно использовать повторно. ПОЦЕЛУЙ. Это предположение может быть правдой; если нет, то читателю предлагается выполнить упражнение, чтобы преобразовать эту логику в помощника.

По второму пункту вы также правы, и действительно нет никакого способа обойти это. Каждая строка, созданная из данных, о которых SQL Server еще не знает, должна вставляться по одной строке за раз. Вы МОЖЕТЕ каким-то образом установить массовую вставку, но я могу гарантировать, что это больше проблем, чем стоит, пока вы не попадете в тысячи записей. Любое ORM, которое вы используете, приведет к тому же SQL.

Если вы не используете ORM: Если вы используете достаточно сложную модель домена / данных, если вы не используете сборный ORM, вы в итоге свернете свою собственную, если хотите, чтобы она соответствовала методологиям проектирования, таким как SOLID.

3 голосов
/ 15 февраля 2011

Это действительно зависит от личных предпочтений и мнений. Некоторые разработчики сказали бы, что в коде, который вы показали, нет ничего плохого. Другие сказали бы, что каждый класс отвечает только за свое состояние и свойства. Другие скажут и другие вещи. Вы должны использовать то, что подходит именно вам, то есть то, с чем вам удобно работать. Лично я предпочитаю использовать EF Code First, который позволяет мне легко создавать классы моей модели и класс контекста базы данных. Затем я просто абстрагирую это, используя шаблон репозитория и класс UnitOfWork, который заботится о фиксации транзакций. Более того, шаблон внедрения зависимостей - отличный способ потерять пару ваших классов. У меня были серьезные проблемы с тесно связанными классами, которые я не мог решить без использования контейнера IoC.

Эта статья , безусловно, является лучшим ресурсом по теме, которую я видел. Автор проделал большую работу по созданию полностью работающей и, что наиболее важно, масштабируемой инфраструктуры для работы.

Удачи:)

...