powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Nhibernate LazyLoading в многослойном приложении
14 сообщений из 14, страница 1 из 1
Nhibernate LazyLoading в многослойном приложении
    #38108511
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго времени суток!

Недавно начал изучать NHibermate и наткнулся на проблему LazyLoading связанных коллекций в приложении, состоящем из нескольких слоев. Структура приложения такова:

1 проект: TestProject.Model
Здесь находятся только лишь сущностные классы. Вынесение этих классов в отдельный проект обусловлено тем, что в идеале хотелось бы абстрагироваться от конкретной ORM.
Пример

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
/// <summary>
/// Инкапсулирует данные об авторе произведения
/// </summary>
public partial class Author
{
   public virtual int AutorID {get;set;}
   ...
   public virtual IList<Books> Books {get;set;}
}



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.
/// <summary>
/// Возвращает книгу по ее названию
/// </summary>
/// <param name="bookName">Название книги</param>
/// <returns>Книга с названием bookName или null, если она не найдена</returns>
public static Author GetBookByName(string bookName)
{
   try
      {
          using(BooksRepository repo=new BooksRepository())
         {
            return repo.GetBookByName(bookName);
         }
      }
      catch
      {
          throw;
      }
}


Приходится писать эти обертки потому, что не хотелось бы давать 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.
public T UnProxyObjectAs<T>(object obj)
{
    return Session.GetSessionImplementation().PersistenceContext.Unproxy(obj) as T;
}


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

Таким образом, прошу помощи в решении следующих вопросов, внятных ответов и примеров на которые найти не удалось:
1. Как все-таки получить в UI вложенную коллекцию через LazyLoading?
2. Можно ли как-то избавиться от оберток в контроллерах, с учетом того, что не хотелось бы давать прямой доступ UI к репозиторию, и при этом многие его методы им все равно используются?
3. Какие исправления можно внести в архитектуру?

Заранее спасибо за ответы.

Возможно, что-то не совсем понятно написал, поэтому отвечу на любые уточняющие вопросы.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38108550
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Yaroslav82,

1. Правильный способ: Выкинуть репозитории, и работать с сессией во время жизни до тех пор, пока она вам нужна.
2. Корявый способ: Использовать NHibernateUtil.Initialize() вместо приведённого вами корявого кода.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38108570
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtor1. Правильный способ: Выкинуть репозитории, и работать с сессией во время жизни до тех пор, пока она вам нужна.

Т.е. вы предлагаете не делить приложение на слои и все писать в одном проекте? А сессию держать, например, в Global.asax?
SolYUtor2. Корявый способ: Использовать NHibernateUtil.Initialize() вместо приведённого вами корявого кода.

Такой способ через Initialize() тоже видел, только опять же непонятно, где его писать.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38109012
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Yaroslav82Т.е. вы предлагаете не делить приложение на слои и все писать в одном проекте? А сессию держать, например, в Global.asax?
Да. Делить не надо. Сессию держать в global.asax и других статических полях категорически не рекомендую. Туда можете запихнуть SessionFactory, а сессия должна жить не более чем webrequest.

Yaroslav82Такой способ через Initialize() тоже видел, только опять же непонятно, где его писать.
После загрузки сущности, пока еще жива сессия.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38109480
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtorДа. Делить не надо

Получается, репозиторий, бизнес-логика и UI будут в одном проекте? Как это согласуется с концепцией многослойных приложений?
SolYUtorСессию держать в global.asax и других статических полях категорически не рекомендую. Туда можете запихнуть SessionFactory, а сессия должна жить не более чем webrequest.
Ну да, я это и имел в виду, не так выразился немного. В Global.asax находится SessionFaсtory, которая возвращает ссылку на текущую сессию.
SolYUtorПосле загрузки сущности, пока еще жива сессия.
Тогда непонятно, как будет реализована ленивая загрузка по запросу (когда одной странице нужна вложенная коллекция, а другой нет). Так можно сделать только если не разделять приложение, и в code-behind страницы писать эту подргрузку. Что опять приводит нас к тому, что все слои будут в одном месте.

Т.е., я так понимаю, архитектурного решения для этой проблемы нет?
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38109506
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Yaroslav82Получается, репозиторий, бизнес-логика и UI будут в одном проекте? Как это согласуется с концепцией многослойных приложений?
Делить можно не только про проектам, но по пространствам имён (папкам) внутри проекта ;)
Слои ради слоёв (как всё остальное ради себя самого) права на жизнь не имеют. Жизнь они вам не облегчат, а вот головной боли добавят.
Yaroslav82Тогда непонятно, как будет реализована ленивая загрузка по запросу (когда одной странице нужна вложенная коллекция, а другой нет). Так можно сделать только если не разделять приложение, и в code-behind страницы писать эту подргрузку. Что опять приводит нас к тому, что все слои будут в одном месте.

Т.е., я так понимаю, архитектурного решения для этой проблемы нет?
Правильно понимаете. Чтобы приложение было эффективно, надо доступ к данным проектировать под конкретный прецедент использования (читай веб-страница). Если писать доступ к данным ради абстракций, слоёв и т.д. получается плохо. Я об этом уже недавно писал 13762820 .
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38109893
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtor,

Спасибо, буду думать
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38110130
SeVa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторПроблема собственно, заключается в том, чтобы понять, как получить вложенные коллекции в TestProject.UI через LazyLoading. Например, одной aspx-странице нужен просто список авторов, а другая использует еще и коллекцию Books. При этом приходит объект BookProxy и при дата-биндинге бросается LazyInitializationException (no session). Почему так происходит - понятно, т.к. aspx-страница обратилась к контроллеру, тот сделал вызов соответствующего метода репозитория, обернув его в using и возвратил коллекцию клиенту. Понятно, что в это время сессия уже закрыта, и получить вложенную коллекцию нельзя.
При копании в интернете наткнулся на такой способ


Использовать DI.
Mef

Unity

Или Вариант без DI
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38110334
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38111161
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SeVa,

Спасибо, почитаю.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38111165
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtor,

Спасибо, эту статью читал. Через http-модуль не очень бы хотелось, поскольку это даст связь между UI и конкретной ORM. Этого бы хотелось избежать.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38111457
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Yaroslav82,

а вы реально пробовали абстрагироваться от ORM? :)
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38112094
Yaroslav82
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtor,

Так вот и хотел попробовать на тестовом проекте. Но видимо, полностью ее использование от вышележащих слоев все равно скрыть не удастся.
...
Рейтинг: 0 / 0
Nhibernate LazyLoading в многослойном приложении
    #38112367
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Yaroslav82,

правильно понимаете. Но можно убедиться. Ничто так не учит, как собственные ошибки.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Nhibernate LazyLoading в многослойном приложении
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]