我刚刚开始使用NHibernate,使用流畅的NHibernate创建了我的映射,如下所示:
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x._id, "Id");
Map(x => x._KdNr, "KdNr");
Map(x => x._Name, "Name");
HasMany(x => x._Contact)
.Table("Contacts")
.KeyColumn("FKCustomerID")
.LazyLoad();
}
}
public class ContactMap : ClassMap<Contact>
{
public ContactMap()
{
Id(x => x._id, "Id");
Map(x => x._Name, "Name");
}
}
为了保存新记录,也可以:
public static void AddCustomer(Customer cust)
{
using (var session = SessionFactory.Instance.OpenSession())
{
session.Save(cust);
session.Save(cust._Contact);
session.Flush();
}
}
然后我尝试选择我添加的客户:
using (var session = SessionFactory.Instance.OpenSession())
{
try
{
var v = session.CreateQuery("from Customer").List<Customers>();
return (List<Customer>)v;
}
catch
{
session.Close();
throw;
}
finally
{
session.Disconnect();
}
}
}
客户也可以正常加载,但内部联系人未引用以下错误:
初始化[fnh.DataModel.Customer#d2f2d1c5-7d9e-4f77-8b4f-9e200088187b] -failed 懒惰地初始化角色集合: fnh.DataModel.Kunde._Contact,没有关闭会话或会话
但我无法理解错误的来源,因为会话在执行我的HQL错误后关闭...
答案 0 :(得分:2)
问题是联系人是延迟加载的,即。在初始查询中不从数据库中提取集合。我假设您将对象直接传递给视图而不是使用viewmodel?你有几个选择,每个都有它们的缺点。
在视图中保持会话打开 正在进行(所谓的开放 会话视图方法)。你可能正在关闭控制器中的NH会话吗?
急切加载整个对象图 使用.Not.Lazyload()就可以了 联系人。 (不推荐)
将您需要的所有数据复制到视图中 控制器中的模型,并通过 这个看法。使用automapper来帮助您。
更新以回复评论:
离开集合延迟加载仍然有很大的好处。当然,在这种情况下,您不会受益于客户对象上的延迟加载联系人,因为您需要使用它们。但在另一个上下文中,您可能只需要客户名称和ID - 并且您可以放心,这不会生成带有连接等的大查询。
要在View中使用Open Session,您不必明确地将会话传递给视图,而只需像以前一样传递对象,但保持会话打开 - 当您尝试访问时,NH将自动生成新查询联系人集合。 (这是有效的,因为客户对象仍然“附加”到幕后的打开会话中)。这里唯一的区别是你需要关闭不在控制器中的会话(当前使用.close()显式关闭会话或者使用'using'隐式关闭会话。关于在何处开启和关闭会议 - 有不同的方法:
在global.asax中 - 在Application_BeginRequest中打开并在Application_EndRequest中关闭(参见:this article)为了简单起见,如果你想在View中进行Open Session,我建议从这开始。
在一个http模块中(基本上与上一个模块相同,但模块化)(见this article)
对于最后两个,你可能会想'但这意味着为每个页面请求创建一个会话!' - 你会是对的,但实际上有多少页不会进入数据库?创建会话工厂后,加上会话创建是轻量级的。
当然,很多人不喜欢View中的Open Session,因为你无法控制纯粹在控制器中生成什么查询 - 视图触发了很多查询,这可能会导致不可预测的性能。
3与2完全不同,因为在不需要延迟加载集合的情况下,它不会从数据库中获取。例如,在这种情况下,您可能正在使用完整的对象图复制到ViewModel,但在另一种情况下,您可能只使用具有客户名称和Id的ViewModel - 在这种情况下,联系人集合的联接不会被不必要地执行。在我看来,3是正确的做事方式 - 但你最终会创建更多的对象(因为视图对象)。