Наследование от классов сущностей и расширение класса

Я использовал Entity Framework 4.0 для создания уровня доступа к данным. Затем я обнаружил, что мой уровень бизнес-логики имеет те же объекты, что и DAL, но с некоторыми расширениями (например, больше свойств, некоторые функции и проверка данных в установщиках...).

Я планировал использовать DAL и BLL в отдельных проектах и ​​искал передовой опыт использования классов сущностей в BLL и предотвращения избыточности кода.

Пока я искал, есть две основные идеи:

  1. расширение классов сущностей внутри одного проекта частичными классами
  2. Использование интерфейсов (реализованных классом сущности и соответствующим классом BLL). Первый более популярен среди программистов.

Недостатки вышеуказанных решений:

  1. Нам нужно добавить код в тот же проект как часть частичного класса. Это хорошо для добавления свойств и методов, но не подходит для переопределения чего-либо (т. е. добавления проверок перед установкой свойства на уровне бизнес-логики).
  2. Если модель сущности изменена, нам нужно снова вручную извлечь интерфейсы из классов сущностей, а также необходимо еще одно изменение в классе, связанном с BLL (два обходных пути вручную).

Мой вопрос: почему мы просто не наследуем наши классы BLL от соответствующих классов сущностей и не расширяем/не переопределяем их методы и свойства?


person Xaqron    schedule 10.02.2011    source источник


Ответы (1)


Одна вещь, которую вам нужно иметь в виду, это то, что ORM, такие как Entity Framework, на самом деле не создают простой уровень доступа к данным (если смотреть через общую трехуровневую архитектуру). То, что они дают вам, — это гораздо больше бизнес-уровня с немного более детальным уровнем контроля над взаимодействием с доступом к данным. Я думаю, можно утверждать, что EF по существу становится вашим DAL, а контекст и типы сущностей могут быть BLL.

Линию намного легче увидеть, если рассматривать ее через архитектуру MVC или MVVM, где у вас есть модель (ваш уровень EF), контроллер или модель представления (где находится бизнес-логика, которая инкапсулирует модель) и представление.

В любом случае, поскольку EF фактически должен создавать экземпляры типов сущностей напрямую, наследование не принесет вам много пользы, поскольку EF не будет использовать ваш подтип в качестве возвращаемой сущности. Решением для проверки и подобных задач в EF является использование как частичных классов (о которых вы, очевидно, знаете), так и частичных методов. Шаблоны генерации кода по умолчанию в EF создают частичные методы для всех скалярных свойств для OnPROPERTYNAMEChanging и OnPROPERTYNAMEChanged.

Например, если у вас есть свойство int UserId для вашего типа объекта User, вы можете создать разделяемый класс, который выглядит следующим образом:

public partial class User
{
    partial void OnUserIdChanging(int newUserId)
    {
        // do something
    }

    partial void OnUserIdChanged()
    {
        // do something
    }
}

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

Другими словами, даже если вы можете зайти в код конструктора и увидеть объявления для

partial void OnUserIdChanging(int value);
partial void OnUserIdChanged();

Если вы на самом деле не добавите тело метода в функцию, то компилятор C# полностью удалит функцию и все вызовы к ней из кода, как будто ее никогда и не было. Это делает типы меньше, а вызовы других свойств быстрее, так как не нужно будет возиться с вызовом пустой функции.

person Adam Robinson    schedule 10.02.2011
comment
Как вы упомянули, например, MVC, где контроллер инкапсулирует режим, я хочу инкапсулировать классы сущностей на более высоком уровне абстракции в отдельном проекте. Я все еще могу передать новый класс в структуру сущностей, поскольку унаследованный класс является типом базового класса сущностей. Я не собираюсь вносить какие-либо изменения в сгенерированный EF код (классы сущностей). Мне нужен собственный BLL, и я хочу сохранить сгенерированный EF код без изменений. Я не хочу, чтобы EF возвращал мои подтипы. - person Xaqron; 11.02.2011
comment
@Xaqron: Дело в том, что MVC и подобные архитектуры работают через инкапсуляцию, а не наследование. Если вы хотите принять такой подход, это прекрасно, но наследование от самих типов сущностей, как правило, не так. - person Adam Robinson; 11.02.2011