我有一个班级DepartmentEntity
,包含一个名为Company(CompanyEntity)
的属性,如下所示:
public class DepartmentEntity
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual DepartmentEntity Parent { get; set; }
public virtual CompanyEntity Company { get; set; }
}
public class CompanyEntity
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
}
DepartmentEntity.hbm.xml
如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="HS.DepartmentEntity, HS" table="DepartmentInfo" lazy="true">
<id name="ID">
<generator class="identity" />
</id>
<property name="Name" not-null="true" />
<many-to-one name="Parent" column="ParentID" class="HS.DepartmentEntity, HS" cascade="none" unique="true" not-found="ignore" lazy="no-proxy" />
<many-to-one name="Company" column="CompanyID" class="HS.CompanyEntity, HS" cascade="none" unique="true" not-found="ignore" lazy="no-proxy" />
</class>
</hibernate-mapping>
CompanyEntity.hbm.xml
如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="HS.CompanyEntity, HS" table="CompanyInfo" lazy="true">
<id name="ID">
<generator class="identity" />
</id>
<property name="Name" not-null="true" />
</class>
</hibernate-mapping>
我试过下面的代码:
IList<DepartmentEntity> list;
using(ISession session = GetSession())
{
string hql = "FROM DepartmentEntity as dpe join fetch dpe.Company";
list = session.CreateQuery(hql).List<DepartmentEntity>();
}
会话结束后,无法访问属性Company
,但如果list方法只找到一条记录,则可以访问属性Company
,我不知道原因。
答案 0 :(得分:0)
NHibernate将会话对象用于Lazy加载导航属性。当您第一次访问导航属性时,NHibernate访问数据存储并使用会话获取对象的值。当会话关闭时,尝试访问该属性会引发类型NHibernate.LazyInitializationException
的异常。
我建议您在需要访问Company属性时尝试保持会话打开,或者您可以关闭应用程序的延迟加载(这可能会降低性能)。
答案 1 :(得分:0)
我假设你的问题是在关闭会话之后,你正在尝试加载一个懒惰的属性。 所以你可以这样做:
if(!NHibernateUtil.IsInitialized(object.Lazy_property) )
NHibernateUtil.Initialize(object.Lazy_property);
但是它会抛出一个异常“集合与任何会话无关”所以你必须打开一个会话,将对象添加到会话中(我通常使用session.saveorUpdate(object))然后初始化惰性属性。
if(!NHibernateUtil.IsInitialized(object.Lazy_property) )
{
//open a session
session.SaveorUpdate(object);
NHibernateUtil.Initialize(object.Lazy_property);
//close the session
}
但您仍然可以获得“具有相同ID的另一个实例在会话中”的异常,因此您必须检查具有相同ID的另一个实例是否在会话中。如果您浏览不同的文档,建议您在将对象添加到会话之前检查session.contains(对象)。
if(!NHibernateUtil.IsInitialized(object.Lazy_property) )
{
//open a session
if (session.Contains(object))
session.evict(object);
Session.SaveorUpdate(object);
NHibernateUtil.Initialize(object.Lazy_property);
//close the session
}
但是它仍然无法解决问题。因为Contains方法适用于不在ID上的实例。所以一个好的方法是使用Load方法:
if (!NHibernateUtil.IsInitialized(object.Lazy_property))
{
//open a session
Class1 temp_object= lSession.Load<Class1>(object.ID);
if (temp_object.ID == Object.ID)
Session.Evict(lProgressItemType);
Session.SaveOrUpdate(this);
NHibernateUtil.Initialize(ProxyMilestoneList);
//close session
}
最好的方法是同时使用Load和Contains:
if (!NHibernateUtil.IsInitialized(object.Lazy_property))
{
//open a session
Class1 temp_object= lSession.Load<Class1>(object.ID);
if (temp_object.ID == object.ID && !Session.Contain(object))
Session.Evict(lProgressItemType);
Session.SaveOrUpdate(this);
NHibernateUtil.Initialize(ProxyMilestoneList);
//close session
}
因为只需检查ID,就可以从会话中删除要对其进行处理的实例,然后再将其添加到会话中。它不会抛出任何异常,但是你击中了DB两次。