|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
Доброго времени суток! Недавно начал изучать NHibermate и наткнулся на проблему LazyLoading связанных коллекций в приложении, состоящем из нескольких слоев. Структура приложения такова: 1 проект: TestProject.Model Здесь находятся только лишь сущностные классы. Вынесение этих классов в отдельный проект обусловлено тем, что в идеале хотелось бы абстрагироваться от конкретной ORM. Пример Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9.
2 проект: TestProject.DAL Здесь находятся репозитории, релизующие CRUD-операции, плюс ряд дополнительных методов, типа GetAuthorByName. В этом же проекте находятся файлы маппингов NHibernate, которые указывают на соответствующие классы в TestProject.Model. Соответственно там же инкапсулировано все, что связано с NHibernate, типа класса SessionManager, который возвращает текущую сессию. 3 проект: TestProject.Logic Здесь находятся контроллеры, которые реализуют бизнес-логику. Например, есть метод, добавляющий новую книгу. При вызове он сначала проверяет бизнес-правила (например, обращается к репозиторию с проверкой, нет ли уже книги с таким же названием и с таким же автором), потом, если все прошло успешно, сохраняет новую книгу в БД опять же при помощи обращения к репозиторию. Кроме того, здесь же находятся обертки над практически всеми методами репозитория, например, метод GetBookByName, который выглядит примерно так: Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.
Приходится писать эти обертки потому, что не хотелось бы давать 4-му проекту (см. ниже) прямой доступ к репозиторию, а некоторые из мелких методов репозитория, например, метод, приведенный выше, требуется в 4-м проекте. 4 проект TestProject.UI. Здесь, собственно находятся ASPX-страницы приложения, которые обращаются к контроллерам, получают данные, сохраняют, редактируют и т.д. В итоге TestProject.DAL ссылается на TestProject.Model, TestProject.Logic - на TestProject.Model и TestProject.DAL, TestProject.UI - на TestProject.Model и TestProject.Logic. Проблема собственно, заключается в том, чтобы понять, как получить вложенные коллекции в TestProject.UI через LazyLoading. Например, одной aspx-странице нужен просто список авторов, а другая использует еще и коллекцию Books. При этом приходит объект BookProxy и при дата-биндинге бросается LazyInitializationException (no session). Почему так происходит - понятно, т.к. aspx-страница обратилась к контроллеру, тот сделал вызов соответствующего метода репозитория, обернув его в using и возвратил коллекцию клиенту. Понятно, что в это время сессия уже закрыта, и получить вложенную коллекцию нельзя. При копании в интернете наткнулся на такой способ Код: c# 1. 2. 3. 4.
Возникает вопрос, куда писать этот метод. В сущностный класс, как реализацию get не хотелось бы, поскольку, как сказано выше, в идеале хотелось бы отвязать модель от ORM. В метод контроллера тоже непонятно, поскольку в этом случае коллекция будет подгружаться видимо всегда, а как написано в приведенном выше примере, одной aspx-странице может потребоваться вложенная коллекция, а другой нет. Писать в UI при дата-биндинге тем более неправильно. Таким образом, прошу помощи в решении следующих вопросов, внятных ответов и примеров на которые найти не удалось: 1. Как все-таки получить в UI вложенную коллекцию через LazyLoading? 2. Можно ли как-то избавиться от оберток в контроллерах, с учетом того, что не хотелось бы давать прямой доступ UI к репозиторию, и при этом многие его методы им все равно используются? 3. Какие исправления можно внести в архитектуру? Заранее спасибо за ответы. Возможно, что-то не совсем понятно написал, поэтому отвечу на любые уточняющие вопросы. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2013, 21:40 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
Yaroslav82, 1. Правильный способ: Выкинуть репозитории, и работать с сессией во время жизни до тех пор, пока она вам нужна. 2. Корявый способ: Использовать NHibernateUtil.Initialize() вместо приведённого вами корявого кода. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2013, 22:41 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
SolYUtor1. Правильный способ: Выкинуть репозитории, и работать с сессией во время жизни до тех пор, пока она вам нужна. Т.е. вы предлагаете не делить приложение на слои и все писать в одном проекте? А сессию держать, например, в Global.asax? SolYUtor2. Корявый способ: Использовать NHibernateUtil.Initialize() вместо приведённого вами корявого кода. Такой способ через Initialize() тоже видел, только опять же непонятно, где его писать. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2013, 23:10 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
Yaroslav82Т.е. вы предлагаете не делить приложение на слои и все писать в одном проекте? А сессию держать, например, в Global.asax? Да. Делить не надо. Сессию держать в global.asax и других статических полях категорически не рекомендую. Туда можете запихнуть SessionFactory, а сессия должна жить не более чем webrequest. Yaroslav82Такой способ через Initialize() тоже видел, только опять же непонятно, где его писать. После загрузки сущности, пока еще жива сессия. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2013, 12:26 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
SolYUtorДа. Делить не надо Получается, репозиторий, бизнес-логика и UI будут в одном проекте? Как это согласуется с концепцией многослойных приложений? SolYUtorСессию держать в global.asax и других статических полях категорически не рекомендую. Туда можете запихнуть SessionFactory, а сессия должна жить не более чем webrequest. Ну да, я это и имел в виду, не так выразился немного. В Global.asax находится SessionFaсtory, которая возвращает ссылку на текущую сессию. SolYUtorПосле загрузки сущности, пока еще жива сессия. Тогда непонятно, как будет реализована ленивая загрузка по запросу (когда одной странице нужна вложенная коллекция, а другой нет). Так можно сделать только если не разделять приложение, и в code-behind страницы писать эту подргрузку. Что опять приводит нас к тому, что все слои будут в одном месте. Т.е., я так понимаю, архитектурного решения для этой проблемы нет? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2013, 15:51 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
Yaroslav82Получается, репозиторий, бизнес-логика и UI будут в одном проекте? Как это согласуется с концепцией многослойных приложений? Делить можно не только про проектам, но по пространствам имён (папкам) внутри проекта ;) Слои ради слоёв (как всё остальное ради себя самого) права на жизнь не имеют. Жизнь они вам не облегчат, а вот головной боли добавят. Yaroslav82Тогда непонятно, как будет реализована ленивая загрузка по запросу (когда одной странице нужна вложенная коллекция, а другой нет). Так можно сделать только если не разделять приложение, и в code-behind страницы писать эту подргрузку. Что опять приводит нас к тому, что все слои будут в одном месте. Т.е., я так понимаю, архитектурного решения для этой проблемы нет? Правильно понимаете. Чтобы приложение было эффективно, надо доступ к данным проектировать под конкретный прецедент использования (читай веб-страница). Если писать доступ к данным ради абстракций, слоёв и т.д. получается плохо. Я об этом уже недавно писал 13762820 . ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2013, 15:59 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
SolYUtor, Спасибо, буду думать ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2013, 19:33 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
авторПроблема собственно, заключается в том, чтобы понять, как получить вложенные коллекции в TestProject.UI через LazyLoading. Например, одной aspx-странице нужен просто список авторов, а другая использует еще и коллекцию Books. При этом приходит объект BookProxy и при дата-биндинге бросается LazyInitializationException (no session). Почему так происходит - понятно, т.к. aspx-страница обратилась к контроллеру, тот сделал вызов соответствующего метода репозитория, обернув его в using и возвратил коллекцию клиенту. Понятно, что в это время сессия уже закрыта, и получить вложенную коллекцию нельзя. При копании в интернете наткнулся на такой способ Использовать DI. Mef Unity Или Вариант без DI ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2013, 23:59 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
15.01.2013, 10:32 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
SeVa, Спасибо, почитаю. ... |
|||
:
Нравится:
Не нравится:
|
|||
15.01.2013, 17:45 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
SolYUtor, Спасибо, эту статью читал. Через http-модуль не очень бы хотелось, поскольку это даст связь между UI и конкретной ORM. Этого бы хотелось избежать. ... |
|||
:
Нравится:
Не нравится:
|
|||
15.01.2013, 17:47 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
Yaroslav82, а вы реально пробовали абстрагироваться от ORM? :) ... |
|||
:
Нравится:
Не нравится:
|
|||
15.01.2013, 21:17 |
|
Nhibernate LazyLoading в многослойном приложении
|
|||
---|---|---|---|
#18+
SolYUtor, Так вот и хотел попробовать на тестовом проекте. Но видимо, полностью ее использование от вышележащих слоев все равно скрыть не удастся. ... |
|||
:
Нравится:
Не нравится:
|
|||
16.01.2013, 13:31 |
|
|
start [/forum/topic.php?fid=17&fpage=29&tid=1350133]: |
0ms |
get settings: |
11ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
52ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
55ms |
get tp. blocked users: |
2ms |
others: | 25ms |
total: | 181ms |
0 / 0 |