2017-01-06 3 views
1

Я прочитал много статей о DDD и понял, что должен использовать классы модели домена на уровне инфраструктуры, поэтому я должен использовать те же классы, что и инфраструктура Entity Framework, и использовать их для генерации таблиц (кодовый подход) и т. д. Но моя модель домена может быть полностью отличной от модели реляционной БД.Классы DDD и Entity Framework

Почему я не могу создать еще одну модель, модель инфраструктуры, чтобы создать реляционную модель БД и не смешивать модель домена с классами EF?

+4

Это нормально, если у вас есть несколько моделей и их использование. Почему вы думаете, что не можете этого сделать? Существует много статей или сообщений в блогах, в которых используются одни и те же классы для домена и хранилища, но это не всегда верно для реальных приложений. – Dennis

+0

Я не вижу здесь никаких ограничений, да, похоже, будет много работы, но эй ... ничего не приходит без усилий –

+0

@OlegSh, что так отличается между вашей объектной моделью и базой данных, что вы не удалось сопоставить его с Entity Framework? Это редко случается в моем опыте. – guillaume31

ответ

2

Рассмотрим простой пример:

домена Модель

public class Customer 
{ 
    public Customer(IRegistrar registrar) 
    { 
     this.registrar = registrar; 
    } 

    public int Age 
    { 
     get 
     { 
      // Just for this example. This will not work for all locals etc but beyond the point here. 
      var today = DateTime.Today; 
      return today.Year - this.DateOfBirth.Year; 
     } 
    } 

    public DateTime DateOfBirth { get; set; } 

    public int Register() 
    { 
     if (this.Age < 18) 
     { 
      throw new InvalidOperationException("You must be at least 18 years old"); 
     } 

     int id = this.registrar.Register(this); 

     return id; 
    } 
} 

public interface IRegistrar 
{ 
    public int Register(Customer customer); 
} 

Многие люди, когда у них нет модели предметной области будет делать это в контроллере MVC:

public ActionResult Search(Customer customer) 
{ 
    var today = DateTime.Today; 
    var age = today.Year - this.DateOfBirth.Year; 
    if (age < 18) 
    { 
     // Return an error page or the same page but with error etc. 
    } 

    // All is good 
    int id = this.registrar.Register(customer); 

    // The rest of code 
} 

Есть несколько проблем с этим:

  1. Что делать, если разработчик забыл сделать проверку на возраст до звонка registrar? Многие скажут, хорошо, что это плохой разработчик. В любом случае, этот тип кода подвержен ошибкам.

  2. Продукт работает хорошо, поэтому финансовый директор решает открыть API, потому что есть много разработчиков, которые создают великолепные интерфейсы пользовательского интерфейса для регистрации клиентов, и они хотят использовать наш API. Таким образом, разработчики идти вперед и создать службу WCF, как это:

    public int Register(Customer customer) 
    { 
        var today = DateTime.Today; 
        var age = today.Year - this.DateOfBirth.Year; 
        if (age < 18) 
        { 
         // Return a SOAP fault or some other error 
        } 
    
        int id = this.registrar.Register(customer); 
    
        // The rest of code 
    } 
    
  3. Теперь разработчики могут забыть сделать проверку возраста в 2 разных местах.

  4. Код также в двух разных местах. Если есть ошибка, нам нужно запомнить ее в двух разных местах.
  5. Если компания начинает работать в тех местах, где установлен возраст совершеннолетия, нам необходимо найти все места и добавить это правило.
  6. Если мы обсуждаем правила с BA, нам нужно просмотреть все приложения и найти правила.

В приведенном выше случае мы имеем только одно правило: возраст должен быть больше 18. Что делать, если у нас было много правил и еще много классов? Вы можете видеть, куда это пойдет.


EF Модель

Ваша модель EF может выглядеть так:

public class Customer 
{ 
    public int Id { get; set; } 
    public DateTime DateOfBirth { get; set; } 

    // It may have a foreign key etc.  
} 

Application Layer Model

И ваша модель MVC зрения, может быть, как это:

public class Customer 
{ 
    // Or instead of Domain.Customer, it may be a CustomerDto which is used 
    // to transfer data from one layer or tier to another. 
    // But you get the point. 
    public Customer(Domain.Customer customer) 
    { 
     this.DateOfBirth = customer.DateOfBirth; 
     this.Age = customer.Age; 
     if (this.DateOfBirth.DayOfYear == DateTime.Today.DayOfYear) 
     { 
      this.Greeting = "Happy Birthday!!!"; 
     } 
    } 
    public int Age { get; set; } 

    [Required(ErrorMessage = "Date of birth is required.")] 
    [Display(Name = "Data of birth")] 
    public DateTime DateOfBirth { get; set; } 

    public string Greeting { get; set; } 
} 

Вопрос о том, сколько моделей EF вы видели с атрибутом Display?Я позволю вам решить, должна ли модель EF заботиться о том, как она отображается в пользовательском интерфейсе. Только предположение, что моя модель EF будет отображаться в пользовательском интерфейсе, неверна. Возможно, единственными потребителями моего класса является еще один веб-сервис. Я не думаю, что Display должно быть в модели EF, но некоторые могут не согласиться со мной; вы делаете звонок.

Есть много вопросов о stackoverflow о людях, которые спрашивают, что когда-то PropertyX требуется, а иногда и нет, как я могу это сделать? Хорошо, если вы не поместили атрибут Required на свою модель EF и используете свою модель EF в своем представлении, тогда у вас не было бы этой проблемы. Будет одна модель для представления, где PropertyX - обязательное поле. Эта модель будет украшать PropertyX атрибутом Required, а другая модель для представления, которая не требует PropertyX, не украсит свойство атрибутом Required.


ViewModels

И тогда вы можете быть ViewModel для клиента для приложения WPF, и вы можете быть яваскриптом ViewModel для интерфейса (KnockoutJS ViewModel).


Заключение и ответ на ваш вопрос

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

Я прочитал аргументы в сети, такие как «этот проект занимает слишком много времени, я просто хочу быстро выкачать что-то, и дать его клиенту и получить деньги». Хорошо, если вы не разрабатываете продукт, который нужно будет поддерживать, и функции будут добавлены к нему, но вы просто разрабатываете небольшой сайт для своего клиента, тогда не используйте этот подход. Никакая конструкция не применяется к каждой ситуации. Дело в том, что ваш дизайн должен быть выбран мудро с учетом будущего.

Также преобразование из модели сущности в домен для модели для MVC не требуется вручную. Там есть библиотеки, которые сделают это для вас легко, например AutoMapper.

Но я должен признать, что в сети есть множество примеров, а также во многих приложениях, где модели сущностей используются повсюду в приложении, а правила реализуются повсюду с нагрузками операторов if.

+0

Не могли бы вы объяснить, почему вы добавляете View Model, MVC, WPF и «Модель уровня приложения» к уравнению, в то время как исходный вопрос касался только модели домена и «модели реляционной БД»? Я не уверен, что основная часть вашего ответа поддерживает ваш заключительный пункт. – guillaume31

+0

Причина, по которой задавался вопрос, заключается в том, что ОП вводит в заблуждение, думая, что это либо домен, либо модель EF, но не оба. Я хотел бы пояснить, что вы можете не только иметь их обоих, но даже у вас может быть одна модель, как в M для вашего MVC (при необходимости) с некоторыми дополнительными атрибутами. И это может не закончиться, и вы можете создать viewmodel для wpf (при необходимости). Как вы думаете, я могу улучшить ответ? Я открыт для предложений. Благодарю. – CodingYoshi

+0

Я бы сказал, что он вводит в заблуждение, чтобы думать, что, как известно, домен и модель EF * должны быть одинаковыми *. Вариант отсутствия модели домена не появляется нигде в его вопросе, поэтому первая часть вашего ответа (с пронумерованным списком) казалась мне странной. Не иметь модель домена, безусловно, может быть проблемой, но на самом деле не тот, который имеет OP. – guillaume31

-1

Отношение это DDD

Когда я прочитал ваш вопрос, я нахожу что-то, что бросается в глаза. Именно это:

Я прочитал много статей о DDD и понял, что я должен использовать свои модели домена классы на уровне инфраструктуры, поэтому, я должен использовать те же классы, как Entity Framework инфраструктуру и использовать их для создания таблицы (подход с кодовым подходом)

Чтобы быть честным, лучшим источником знаний DDD он по-прежнему является Синей книгой. Я знаю, я знаю, он толст и прост в чтении. Можете взглянуть на DDD Distilled by Vernon. Вывод должен состоять в том, что DDD на самом деле не связан с упорством, а в более глубоком понимании области, лучше понимая ваших экспертов в области.Определенно, он ничего не говорит об ORM.

модели домена Domain Model живучесть

обычно состоят из объектов (если мы говорим о объектно-ориентированных моделей) с состоянием и поведением. Модель имеет одно или несколько объектов и может быть некоторыми объектами значений. Во многих случаях у вас есть только одна сущность в ограниченном контексте. Объекты сгруппированы в Агрегаты, которые изменяются вместе, образуя границы транзакций. Это означает, что каждое изменение в пределах Агрегат представляет собой одну транзакцию, независимо от того, сколько сущностей это изменение коснется. Каждый Агрегат имеет одно и только одно лицо, Совокупный корень, который раскрывает общедоступные методы для других, чтобы работать со всем Совокупный.

Так что ваш Repository должен заботиться о:

  • Упорно всего агрегатного (независимо от того, сколько элементов есть) в рамках одной транзакции, для новых и модернизируемых объектов
  • Fetching всех Агрегат из вашего хранилища настойчивости, по его личности (Агрегатный кореньId property)

Вам наверняка понадобятся некоторые Запросы, но они могут запросить, как они хотят, как только они не изменят состояние модели домена. Многие добавляют методы запросов в репозиторий , но это зависит от вас. Я бы реализовал их как отдельный статический класс с методами расширения DbContext.

Модели не соответствующие друг другу

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

  • Держите государство отдельно от поведения и обладайте его как свойство в объекте домена. Как Order с AddLine и так далее, и OrderState со всеми этими Total, CustomerId и тому подобное. Имейте в виду, что это может не сработать для сложных агрегатов.
  • Концентрат на двух основных методах Репозиторий, о котором я говорил выше, - Add и Get. Каждый Репозиторий работает только для одного типа Агрегат и как вы можете сопоставить их между собой.
  • В сочетании с вышеуказанной точкой вы можете пересмотреть использование ORM и сделать что-то еще. В основном вы можете просто использовать ADO.NET, но проще всего использовать какой-то документ-ориентированный материал, такой как NoSQL, хотя многие не согласятся. Также проверьте this article о хранилище PostgreSQL JSONB как настойчивость.

Помните, что главное, чтобы иметь Repository, который будет делать работу за вас и потенциально (возможно, это никогда не произойдет, но все же) использовать другой магазин.

Вы также можете быть заинтересованы в другом Vernon's article, где он обсуждает использование EF специально.

+1

Мы все любим downvotes без комментариев, не так ли? –

Смежные вопросы