Подтвердить что ты не робот

Путаница о том, где поставить бизнес-логику при использовании инфраструктуры Entity

Я только начал работать с инфраструктурой Entity, и я смущен тем, как классы, обычно входящие в бизнес-уровень, вписываются в объекты, созданные Entity Framework.

При работе с классическим ADO.NET у меня был бы класс под названием Customer, а затем еще один класс под названием DALCustomer для обработки взаимодействия с базами данных. В этой структуре я бы поставил код на выполнение вычислений, фильтрацию и обработку экземпляра DAL с клиентом для сохранения, обновления и удаления в классе Customer.

С помощью платформы Entity Framework, если у вас есть таблица Customer, инфраструктура Entity создает объект под названием Customer, и вот где начинается моя путаница, удаляет ли этот объект потребность в клиенте на бизнес-уровне? Итак, по существу все поля и методы, которые обычно входят в бизнес-уровень, входят в сущность, сгенерированную Entity Framework? Или, если класс еще существует в бизнес-слое CustomerBL, например, который по-прежнему содержит поля и методы, необходимые для выполнения бизнес-логики, необходимой для вычислений, фильтрации и все еще нуждается в экземпляре EF DAL, объявленном для обработки доступа к данным?

Если должен быть бизнес-класс, в данном случае CustomerBL, возникает еще один вопрос, если поля, созданные в объекте клиента, будут воссозданы в CustomerBL или должен быть объявлен экземпляр объекта Customer в CustomerBL, так что не было бы необходимости объявлять поля в двух местах?

4b9b3361

Ответ 1

Структура Entity, в отличие от linq-to-sql, например, была разработана с учетом разделения модели данных и концептуальной модели. Он поддерживает inheritance, разделение объектов, разбиение таблицы, сложные типы и прозрачные ассоциации "многие-ко-многим" , все из которых позволяют форматировать модель домена для удовлетворения потребностей, не слишком сильно ограничивая модель хранилища данных.

Первый подход кода позволяет работать с POCO, в котором выбранные свойства могут быть сопоставлены столбцам хранилища данных. Сначала Model-first и Database-first генерируют частичные классы, позволяя расширять сгенерированный код. Работа с этими классами в значительной степени связана с работой POCOs. Еще больше, начиная с версии 5, когда DbContext стал стандартным API, поэтому сгенерированные классы больше не были набиты кодом, связанным с сохранением, в API ObjectContext.

Конечно, это разделение концептуальной модели и модели магазина может только быть достигнуто в определенной степени. Некоторые вещи работают против этой цели сохранения невежества. Например, если требуется ленивая загрузка, необходимо объявить свойства навигации как virtual, поэтому EF может переопределить их в прокси-типах. И очень удобно иметь примитивные свойства внешнего ключа (например, ParentId), сопровождающие "реальные" ассоциации (a Parent reference). Пуристы считают это нарушением правил, управляемых доменом.

Другим важным нарушением упорства в невежестве является большое количество различий между linq-to-objects и linq-to-entity. Вы просто не можете игнорировать тот факт, что вы связаны с совершенно другим универсумом, чем с объектами в памяти. Это называется плотная связь или нечеткая абстракция.

Но тогда... вообще, я доволен использованием сгенерированных классов EF или POCOs из первой модели кода в качестве классов домена. До сих пор я никогда не видел перехода на трение от одного хранилища данных к другому, если это вообще происходит. Сохранение невежества - это вымысел. Особенности DAL всегда оставляют след в области. Только когда вам нужно кодировать разные хранилища данных/модели или когда магазины/модели, как ожидается, будут меняться относительно часто, это окупается, чтобы максимально уменьшить этот след или полностью абстрагировать его.

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

Ответ 2

По моему мнению, весь смысл использования POCOs в качестве объектов, которые могут быть сохранены, заключается в устранении различия между "сущностями базы данных" и "бизнес-субъектами". "Сущности" должны быть "бизнес-сущностями", которые непосредственно могут сохраняться и загружаться из хранилища данных и, следовательно, одновременно действовать как "сущности базы данных". Используя POCOs, бизнес-объекты отделены от конкретного механизма для взаимодействия с базой данных.

Вы можете переместить объекты в отдельный проект - например, - который не имеет ссылок на какую-либо сборку EF и все же использует их в проекте уровня базы данных для управления сохранением.

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

  • Вы должны сделать свойства навигации (ссылки или коллекции ссылок на другие объекты) virtual для поддержки ленивой загрузки с помощью EF
  • Вы не можете использовать IEnumerable<T> для коллекций, которые необходимо сохранить. Он должен быть ICollection<T> или более производным.
  • Нелегко сохранить свойства private
  • Тип char не поддерживается EF, и вы не можете его использовать, если хотите сохранить его значения.
  • и многое другое...

Но дополнительный набор объектов - на мой взгляд - дополнительный уровень сложности, который должен быть оправдан, чтобы быть действительно необходимым, если указанные ограничения слишком жесткие для вашего проекта.

YA2C (Еще 2 цента:))

Ответ 3

Я не знаю, считал ли он хорошую практику другими, но лично это так, как я справлялся с этим в прошлом:

Классы, созданные EF, являются вашим DAL, а затем для BL создают дополнительный набор классов, в которых у вас будет требуемая структура (например, возможно объединение данных из связанных объектов в отношениях один к одному) и другую бизнес-логику (пользовательская проверка, например, реализация IDataErrorInfo, чтобы она играла хорошо с пользовательским интерфейсом в WPF, например), а также создавать классы, которые будут содержать все методы бизнес-уровня, относящиеся к типу сущности, которые используют экземпляры BL и конвертируют в от объектов EF до объектов BL.

Итак, например, у вас есть Клиент в своем db. EF будет генерировать класс Customer, а в BL будет класс Customer (префикс, суффикс и т.д.) И класс CustomerLogic. В классе BL Customer вы можете делать все, что необходимо для удовлетворения требований, без необходимости вмешиваться в объекты EF, а в классе CustomerLogic у вас бы были методы BL (загрузка самых уважаемых клиентов, сохранение клиентов с дополнительными данными и т.д.).

Теперь это позволит вам быть слабо связанными с реализацией источника данных. Еще один пример того, почему это мне помогло в прошлом (в проекте WPF), состоит в том, что вы можете делать такие вещи, как реализовать IDataErrorInfo и реализовывать логику проверки в классах CustomerBL, чтобы при привязке объекта к форме создания/редактирования в пользовательском интерфейсе вы получите преимущества от встроенных функций, предоставляемых WPF.

... Мои 2 цента, мне также интересно узнать, что такое лучшая практика или какие другие решения/точки зрения.


Также, возможно, связанный с этим темой - Code-first vs Model/Database-first

Ответ 5

Я использовал бизнес-логику для написания своих методов и возврата результатов в созданном виде, например:

namespace Template.BusinessLogic
{
    public interface IApplicantBusiness
    {
        List<Template.Model.ApplicantView> GetAllApplicants();

        void InsertApplicant(Template.Model.ApplicantView applicant);
    }
}