我有一个使用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, 没有会话或会话被关闭
这有什么意义吗?我该如何解决?
答案 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();
}
}
}