Рассмотрим простой пример:
домена Модель
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
}
Есть несколько проблем с этим:
Что делать, если разработчик забыл сделать проверку на возраст до звонка registrar
? Многие скажут, хорошо, что это плохой разработчик. В любом случае, этот тип кода подвержен ошибкам.
Продукт работает хорошо, поэтому финансовый директор решает открыть 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
}
Теперь разработчики могут забыть сделать проверку возраста в 2 разных местах.
- Код также в двух разных местах. Если есть ошибка, нам нужно запомнить ее в двух разных местах.
- Если компания начинает работать в тех местах, где установлен возраст совершеннолетия, нам необходимо найти все места и добавить это правило.
- Если мы обсуждаем правила с 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.
Это нормально, если у вас есть несколько моделей и их использование. Почему вы думаете, что не можете этого сделать? Существует много статей или сообщений в блогах, в которых используются одни и те же классы для домена и хранилища, но это не всегда верно для реальных приложений. – Dennis
Я не вижу здесь никаких ограничений, да, похоже, будет много работы, но эй ... ничего не приходит без усилий –
@OlegSh, что так отличается между вашей объектной моделью и базой данных, что вы не удалось сопоставить его с Entity Framework? Это редко случается в моем опыте. – guillaume31