2

我有一个类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无法访问属性,但如果列表方法只找到一条记录,则Company可以访问属性,我不知道为什么。

4

2 回答 2

0

NHibernate 使用会话对象来延迟加载导航属性。当您第一次访问导航属性时,NHibernate 访问数据存储并使用会话获取对象的值。当会话关闭时,尝试访问该属性会引发类型异常NHibernate.LazyInitializationException

我建议您在需要访问 Company 属性时尝试保持会话打开,或者您可以关闭应用程序的延迟加载(这可能会降低性能)。

于 2013-03-03T21:35:26.123 回答
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(object)。

 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,您就可以从会话中删除您想要处理的实例,然后再次将其添加到会话中。它不会引发任何异常,但您两次访问数据库。

于 2015-06-04T15:22:06.153 回答