Entity Framework DAL, BLL с шаблоном репозитория

Я пытаюсь построить трехуровневую архитектуру с пользовательским интерфейсом, BLL и DAL. Я использую Entity Framework с шаблоном репозитория.

Мой вопрос: должны ли сущности, созданные Entity Framework, действовать как часть моего BLL, или это просто объекты DAL?

Причина, по которой я спрашиваю, заключается в том, что мне кажется, что я копирую код. Например: у меня есть DAL.CatEntity, который создается Entity Framework непосредственно из моей базы данных. Все это прекрасно и модно. Затем я использую свой репозиторий (который является частью моего DAL) для извлечения данных в DAL.CatEntity. Затем я использую этот DAL.CatEntity в своем BLL, извлекаю все его данные и преобразую их в BLL.Cat. Затем я использую этот BLL.Cat в своем слое пользовательского интерфейса.

Ниже приведен очень упрощенный код.

BLL

public Cat GetCat(string catName){
    CatEntityRepository _repository = new CatEntityRepository;
    Cat cat = null;
    CatEntity catEntity = _repository.GetSingleCat();
    cat = ConvertToCat(catEntity);
    return cat;
}

private Cat ConvertToCat(CatEntity entity){
    return new Cat(){
        Name = entity.Name,
        Color = entity.Color,
        //....
    }
}

UI:

public ActionResult method(){
    Cat cat = BLL.GetCat();
    //......
}

Кажется, нет необходимости иметь ОБЕ Cat и CatEntity. Могу ли я просто использовать свои EntityFramework Entities как часть моего BLL при использовании репозитория в качестве моей DLL?

Спасибо.


person Josh Claxton    schedule 08.09.2012    source источник
comment
Возможно, вам будет лучше использовать что-то вроде AutoMapper, а не создавать свои собственные классы сопоставления. Требуется гораздо меньше усилий.   -  person Erik Funkenbusch    schedule 08.09.2012


Ответы (3)


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

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

При этом, на мой взгляд, в большом количестве приложений малой и средней сложности вы можете эффективно рассматривать свои сущности как бизнес-объекты. В частности, если вы сделаете объекты POCO частью своего бизнес-уровня, а затем используете эти объекты в своем EF DAL, это может быть довольно эффективным.

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

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

person Erik Funkenbusch    schedule 08.09.2012
comment
Отличные баллы. Мое приложение будет состоять из веб-сайта и отдельной веб-службы. Оба они должны будут иметь доступ к одному и тому же BLL. Более того, переход на использование веб-службы для доступа к моим данным вполне может произойти в будущем. Похоже, это незначительное дублирование кода вполне может окупиться в будущем. - person Josh Claxton; 08.09.2012
comment
@Kiwi: возврат сущностей ef из репозиториев и их преобразование извне - один из худших подходов. Если вы хотите преобразовать, сделайте это внутри репозитория и выставьте преобразованные объекты. Обратитесь к книге Марка Симанна «Внедрение зависимостей в .NET». - person Wiktor Zychla; 09.09.2012

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

person Darin Dimitrov    schedule 08.09.2012

Альтернативный подход заключается не в ПРЕОБРАЗОВАНИИ между двумя типами объектов, а в создании интерфейсов из сущностей вашего домена и кодировании ваших репозиториев в соответствии с интерфейсами.

Таким образом, вы испечете два торта одновременно. Вы не конвертируете свои объекты уровня данных в объекты bll, и все же вы не путаете слои (в том смысле, что ваши репозитории не работают с конкретными типами слоев данных).

Этот подход на удивление полезен и, тем не менее, редко описывается.

person Wiktor Zychla    schedule 08.09.2012
comment
На самом деле я использую общий интерфейс репозитория для доступа ко всем своим данным. (Я упростил приведенный выше код.) Это то, о чем вы говорили? Если это так, я все еще не понимаю, как мне не нужно конвертировать. - person Josh Claxton; 08.09.2012
comment
Нет. Я говорю об интерфейсах ваших сущностей. Для объекта Cat создайте интерфейс ICat и запрограммируйте свой репозиторий в соответствии с этими интерфейсами домена. Таким образом, НЕТ преобразования, поскольку ваши классы EF будут реализовывать эти доменные интерфейсы. Если когда-нибудь в будущем вы измените реализацию репозитория, вы заставите свои новые классы домена реализовывать те же интерфейсы домена. Кроме того, его легко реализовать в репозиториях памяти, используя классы хранилища памяти и вспомогательные доменные классы, реализующие одни и те же интерфейсы. И все же конверсия не требуется. - person Wiktor Zychla; 08.09.2012
comment
Отсутствие преобразования означает, что ваш код чище и быстрее. И вы по-прежнему сохраняете преимущество отказа от кода для конкретных классов. Разница в том, что с вашим подходом вы кодируете свой слой bll против сущностей bll. В моем подходе вы кодируете против интерфейсов. - person Wiktor Zychla; 08.09.2012
comment
@WiktorZychla - Проблема с вашим подходом в том, что он заставляет ваш уровень данных зависеть от вашего бизнес-уровня, а не наоборот. Это не обязательно проблема, но об этом нужно знать. - person Erik Funkenbusch; 08.09.2012
comment
@MystereMan: не могли бы вы подробнее рассказать об этом? Как вы думаете, почему существует зависимость? Я не вижу ни одного. Интерфейсы домена определяются на уровне домена, один ниже уровня данных, два уровня ниже уровня bll. Уровень данных вообще НЕ осведомлен о слое bll. - person Wiktor Zychla; 08.09.2012
comment
@WiktorZychla - у вас есть странные определения. Я никогда не слышал, чтобы кто-то претендовал на уровень домена ниже уровня данных. Уровень домена обычно совпадает с бизнес-уровнем. - person Erik Funkenbusch; 09.09.2012
comment
@MystereMan: почему вы сейчас обсуждаете определения? Я думал, вы заметили зависимость, которую я не вижу. Мы уже некоторое время успешно создаем приложения с доменными интерфейсами в репозиториях, и, честно говоря, мне действительно любопытно, почему люди настаивают на дорогостоящем копировании вместо кодирования на основе интерфейсов. Я могу написать об этом в ближайшее время. - person Wiktor Zychla; 09.09.2012
comment
@WiktorZychla - почему я обсуждаю определения? Поскольку обычное определение домена - это бизнес, и когда вы сказали, что ваш уровень данных реализует интерфейсы домена, естественным предположением было то, что вы имели в виду, что уровень данных зависит от бизнес-уровня (то есть уровня домена). Не понимаю, как вы этого не понимаете. Но здесь есть и другие проблемы. Например, при использовании определенных технологий вы не хотите платить за объект уровня данных (сам экземпляр) уязвимой части приложения (например, пользовательскому интерфейсу). Использование интерфейсов не решает этой проблемы. - person Erik Funkenbusch; 09.09.2012
comment
@WiktorZychla - Entity Framework автоматически генерирует мои сущности. Следовательно, если бы я создавал интерфейс, я бы по сути копировал типы данных объекта. Это то, что я уже делаю с BLL. Я мог подумать, что это может быть полезно, если мне нужно использовать его более двух раз, но я не буду. Возможно, я вас неправильно понял, но это кажется мне чрезмерным. Особенно, если это означает создание еще одного слоя. - person Josh Claxton; 09.09.2012
comment
@MystereMan: правда об этой возможной проблеме. Я не считаю, что это серьезно, поскольку вы передаете объекты с помощью интерфейсов, но я также не отрицаю, что проблема существует. Однако проблема с копированием сущностей домена в том, что это дорого. Из двух вариантов можно выбрать своего любимого. - person Wiktor Zychla; 09.09.2012
comment
@kiwi: так же, как ваши классы ef генерируются автоматически, ваши интерфейсы могут быть сгенерированы. Дублирование здесь не проблема. Проблема в разделении. У вас есть только два варианта. Вы либо копируете свои объекты, либо скрываете их за интерфейсами. Остающийся вариант - ничего не делать - не является выбором, поскольку у вас есть классы ef на бизнес-уровне, что противоречит шаблону репозитория. Вы говорите, что не будете делать это дважды, тогда зачем вам вообще нужен репозиторий, а не кодировать ваш bll напрямую против ef? Если вы неправильно используете репозиторий, зачем он вообще вам нужен? - person Wiktor Zychla; 09.09.2012
comment
@WiktorZychla - Мой репозиторий обращается к моей БД и возвращает объект EF. Затем этот объект EF обрабатывается в моем BLL, который возвращает объекты BLL, которые будут использоваться моим пользовательским интерфейсом. Как это неправильное использование шаблона репозитория? Если мой репозиторий начинает возвращать объекты BLL, значит, я нарушил многоуровневый интерфейс UI- ›BLL-› DAL, в котором мой DAL ссылается на мой BLL. - person Josh Claxton; 09.09.2012