Добавление бизнес-уровня в ADO .NET Entity Framework

Я работаю над своим первым проектом .NET (.NET 3.5, ADO.NET и C#). Мы построили наши модели сущностей и пытаемся создать чистый слой бизнес-объектов.

У нас есть базовая модель объекта, и мы хотим добавить определенную семантику бизнес-уровня к средствам доступа к данным по умолчанию (свойствам навигации и т. д.).

Например, предположим, что у нас есть отношение «многие ко многим» между Person и BankAccounts. Предположим, что на бизнес-уровне мы хотели бы добавить возможность заморозить учетную запись. Теперь нам нужна возможность перехода от Person к:

  • все их банковские счета,
  • их незаблокированные банковские счета, и
  • их замороженные банковские счета.

Естественно, мы хотели бы сделать номинальный случай значением по умолчанию: если я перехожу Person.BankAccounts(), я бы хотел, чтобы он возвращал их незамороженные счета. Я мог бы добавить свойства навигации Person.FrozenBankAccounts() и Person.AllBankAccounts().

Оба подхода, которые мы придумали, кажутся изрядно попахивающими кодом.

  1. Мы не можем найти способ переопределить методы модели сущности. Итак, оставьте Person.BankAccounts() в качестве метода доступа, который возвращает все банковские счета. Затем мы добавляем Person.FrozenBankAccounts() и Person.NonFrozenBankAccounts().
  2. Добавьте еще один явный слой в кодовую базу, который обертывает все обращения к BankAccounts.

С подходом 1 проблема заключается в том, что номинальный бизнес-кейс (доступ к разблокированным банковским счетам) является самым неинтуитивным названием метода лота.

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

Есть ли лучший подход, чем два, которые мы рассмотрели? Если нет лучшего подхода, какой из двух, которые я описал, кажется лучшим решением (учитывая, что у нас есть около 50+ классов, с которыми нам нужно работать)?

Примечание. При поиске в Интернете я нашел открытое письмо в Microsoft под названием Выражение недоверия ADO .NET Entity Framework, которое, по-видимому, подразумевает, что нет хорошего способа добавить четкое разделение проблем.


person Bradley Mazurek    schedule 11.01.2009    source источник


Ответы (4)


У меня нет опыта работы с LINQ to Entities, но ваш вопрос прозвучал звонком. В моем последнем проекте у меня были почти такие же проблемы с другим ORM. Вместо того, чтобы позволять клиентам уровня бизнес-объектов напрямую использовать сгенерированные ORM классы или дублировать все классы и реализовывать массу функций пересылки, я определил интерфейсы. Клиенты вашего уровня бизнес-объектов будут видеть только эти интерфейсы, и ваши классы Entity будут реализовывать эти интерфейсы со следующими преимуществами:

  • В прямом случае (без бизнес-логики) накладные расходы на разработку интерфейсов минимальны. Для большинства членов вам не нужно реализовывать функции пересылки, просто «извлеките» класс сущности из интерфейса и покончите с этим.
  • В случае, который вы упоминаете, в интерфейсе вы можете иметь свойство BankAccounts и через явную реализацию интерфейса разрешить его пересылку в NonFrozenBankAccounts реализующего объекта. Вы, конечно, также можете добавить любые проверки, которые вы хотите
  • В качестве дополнительного преимущества вы можете легко заменить базовый уровень сохраняемости без видимых изменений кода клиента.
person Community    schedule 11.01.2009

Вы можете добавить два новых типа сущностей, наследуемых от Account
— RegularAccount и FrozenAccount
, а также добавить поле IsFrozen в качестве условия наследования (таблица для каждой иерархии).

Затем вы можете удалить ассоциацию с «Лицо» на «Учетная запись» и создать две новые ассоциации:

Person to RegularAccount, имя свойства навигации для человека "Accounts".

Лицо для FrozenAccount, имя свойства навигации для человека «FrozenAccounts».

person Danny Varod    schedule 12.04.2011

Один из способов сделать это будет выглядеть так:

  1. Определите свое свойство AllBankAccounts (возможно, даже сделайте его частным).
  2. Определите свойство BankAccounts в частичном классе Person. Свойство может быть выражено в терминах AllBankAccounts с использованием LINQ, т. е. AllBankAccounts.Where(a => !a.IsFrozen)
  3. Определите свойство FrozenBankAccounts в частичном классе Person, как на шаге 2.

Надеюсь, это поможет.

person Andrew Peters    schedule 20.02.2009

Откажитесь от EF в пользу NHibernate.

Способ NHibernate таков: вы создаете бизнес-объекты и указываете NHibernate, как эти бизнес-объекты должны быть сохранены в базе данных. Сами бизнес-объекты не знают, как они сохраняются или загружаются, или что используется NHibernate. Это называется «Упорство в неведении». Кроме того, вы можете указать NHibernate сохранять и загружать ваши бизнес-объекты практически любым удобным для вас способом. Он имеет хорошую поддержку сценария, который вы описываете.

Прекратите писать уровни доступа к данным и перестаньте создавать для них код. Используйте реальный мужской ORM.

person yfeldblum    schedule 11.01.2009
comment
Хороший подход, однако его можно реализовать и с EF4. - person Danny Varod; 12.04.2011