会话关闭后无法访问引用的对象

时间:2012-09-03 15:15:28

标签: c# nhibernate

我有一个班级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,我不知道原因。

2 个答案:

答案 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两次。