HasMany,延迟加载和会话范围的问题

时间:2011-03-27 12:24:37

标签: nhibernate session activerecord lazy-loading castle-activerecord

我有一个使用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")));

我正在使用ActiveRecordMediator的FindAll()方法调用提取 在我的模型中,我有这个属性:

[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] -failed   懒洋洋地初始化一个集合   角色:   Danel.Nursing.Model.AccountService.ServiceOrders,   没有会话或会话被关闭

这有什么意义吗?我该如何解决?

2 个答案:

答案 0 :(得分:1)

使用延迟加载时,将所有访问延迟加载关系的代码放在单个 SessionScope中。否则你将获得异常(除非你手动将实体重新附加到新会话,这通常很麻烦)。

另一个选择是急切地获取你需要的一切(而不是使用延迟加载)。

答案 1 :(得分:0)

以下是我向NHUsers小组发表的帖子的副本(Link to the discussion, which discusses several other approaches as well

我知道你有一个控制台应用程序,我的应用程序是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();
            }
        }
    }