Проблемы с HasMany, отложенной загрузкой и областями сессии - PullRequest
1 голос
/ 27 марта 2011

У меня есть консольное приложение, которое использует NHibernate и ActiveRecord.

Я использую следующие независимые критерии:

DetachedCriteria criteria = DetachedCriteria.For<ServiceOrder>();

            criteria.Add(Restrictions.Lt("End", DateTime.Today.AddDays(3)));
            criteria.Add(new Disjunction()
                            .Add(Restrictions.IsNull("StopReason"))
                            .Add(Restrictions.Eq("StopReason", ServiceStopReason.Worthiness)));

            criteria.Add(new Disjunction()
                            .Add(Restrictions.IsNull("StopDate"))
                            .Add(Restrictions.EqProperty("StopDate", "End")));

И я вызываю выборку с помощью метода FindAll () ActiveRecordMediator.
В моей модели у меня есть это свойство:

[HasMany(Lazy = true)]
public virtual ISet<ServiceOrder> ServiceOrders
{
    get { return serviceOrders; }
    set { serviceOrders = value; }
}

К которому я пытаюсь получить доступ в следующем запросе Linq:

from serviceOrder in serviceOrderDataService.GetServiceOrdersWithEndOfEntitlement()
     let accountGetService = serviceOrder.AccountGetService
     where accountGetService != null
     let serviceOrders = accountGetService.ServiceOrders
     where serviceOrders != null && serviceOrders.Count != 0
     let isFutureServiceOrder = (from accountGetServiceServiceOrder in serviceOrders
                                      where serviceOrder.Start.HasValue
                                      && accountGetServiceServiceOrder.End.HasValue
                                      && serviceOrder.Start > accountGetServiceServiceOrder.End
                                      select accountGetServiceServiceOrder).Any()
     where !isFutureServiceOrder
     select serviceOrder;

Но я получаю следующее исключение:

Инициализация [Danel.Nursing.Model.AccountService # 61786367-e8da-4929-b91b-a7497cf7db10] не смогла лениво инициализировать набор ролей: Danel.Nursing.Model.AccountSrviceService.Service.Service.ни один сеанс или сеанс не был закрыт

Имеет ли это смысл?Как мне это решить?

Ответы [ 2 ]

1 голос
/ 28 марта 2011

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

Другой вариант - быстро выбрать все, что вам нужно (вместо использования отложенной загрузки).

0 голосов
/ 28 марта 2011

Вот копия сообщения, которое я сделал в группе NHUsers ( Ссылка на обсуждение, в котором также обсуждаются несколько других подходов )

Я знаю, что у вас есть консольное приложение, имое приложение - WinForms, но тот же подход должен работать и для вас.Это не идеально, но пока что работает на меня.

=====================================================

Управление сессиями при использовании NHibernate, отложенной загрузки и WinForms кажется тем, с чем многие люди борются - язнайте, что я сделал!

Добавление привязки данных WinForms к миксу является дополнительным усложнением в моем проекте, который имеет единственную основную форму, сосредоточенную вокруг стороннего элемента управления сеткой.Сетка привязана к моей объектной модели через интерфейс IBindingList.

После долгой борьбы и растягивания волос подход, который , похоже, работает , состоит в том, чтобы создать MainSession дляОсновная форма, которая остается открытой большую часть времени.Это означает, что всякий раз, когда пользователи перемещаются по данным с помощью сетки, существует открытый сеанс для обработки ленивых загрузок данных из базы данных.

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

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

И наоборот, если все в порядке, я бы тоже хотел это знать - теперь я буду спать лучше.

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

    /// <summary>
    /// NHibernate session factory used by the application
    /// </summary>
    private static ISessionFactory _sessionFactory;

   /// <summary>
    /// NHibernate session used by MainForm. Kept open most of the time to facilitate
    /// lazy loading of data.  Disconnected and Reconnected when app writes
    /// new data to database
    /// </summary>
    private static ISession _mainSession;

    /// <summary>
    /// Get the main database session, creating it if necessary
    /// </summary>
    /// <returns></returns>
    private static ISession GetMainSession()
    {
        if (_sessionFactory == null)
        {
            CreateSqliteSessionFactory();
        }

        if (_mainSession == null)
        {
            _mainSession = _sessionFactory.OpenSession();
        }

        return _mainSession;
    }

    private static void DisconnectMainSession()
    {
        GetMainSession().Disconnect();
    }

    private static void ReconnectMainSession()
    {
        GetMainSession().Reconnect();
    }

    /// <summary>
    /// Save measurement to DB. Does not check for duplicates
    /// </summary>
    /// <param name="measurement"></param>
    public static void SaveMeasurement(object measurement)
    {
        DisconnectMainSession();

        using (var session = _sessionFactory.OpenSession())
        using (var transaction = session.BeginTransaction())
        {
            try
            {
                session.Save(measurement);

                transaction.Commit();

                session.Close();
            }
            catch (Exception e)
            {
                if (transaction != null) transaction.Rollback();

                throw new ApplicationException(
                    "\r\n    SaveMeasurement exception:\r\n\r\n", e);
            }
            finally
            {
                ReconnectMainSession();
            }
        }
    } 
...