2

我有一些对象,其中一些具有文档列表,其他对象,......等等。我不想lazy=false在关系上使用,因为它使应用程序非常慢。我可以使用 Lock 重新附加对象,以便在需要时加载其他属性或一对多关系。但是对于集合,如果我尝试访问它们,我总是会得到“无法初始化集合”。Lock(obj)如果我调用连接到该位置的对象,它将不起作用。

我希望我的映射看起来像这样:

<set name="DocumentList" table="material_document" cascade="all" lazy="true">
  <key column="material_id"/>
  <many-to-many class="Document">
    <column name="document_id"/>
  </many-to-many>
</set>

有没有办法重新连接?还是有映射设置?

更新1:

这是物质方面的映射:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
<class name="Material" table="material">
<!-- Defining PK -->
<id name="Id" type="integer" column="id">
    <generator class="sequence">
      <param name="sequence">material_id_seq</param>
    </generator>
</id>
<!-- Defining Properties -->
<!-- Defining FK-Relations -->
<set name="DocumentList" table="material_document" cascade="all" lazy="false">
  <key column="material_id"/>
  <many-to-many class="Document">
    <column name="document_id"/>
  </many-to-many>
</set>

文档映射文件没有关于关系的任何信息。数据库名称没问题,其他一切正常。这些表称为material和。我的课程是和属性。我的实体有什么问题?您的意思是数据有问题还是程序中的对象可能发生了某些事情......?material_documentdocumentpublicpublic virtual

List material = LoadAllMaterials();
//some code, that causes the session to be closed, a new session will be opened
foreach (Document d in material.DocumentList) { //causes the exception
    //do something
}

在此之前,我想获取文档,而不是事先加载它们。

更新 2: 我目前如何重新附加对象:当我知道有代理并且它不能以另一种方式工作时,我将 force true 设置为……而且我必须检查它是否在会话中,因为如果我调用它,evict 会抛出一个异常在不在会话中的对象上。

public void Reattach(Type type, BaseObject o, bool force)
{
    bool inSession = o.IsInSession();

    if (force && inSession)
    {
        GetSession().Evict(o);
        GetSession().Lock(type.ToString(), o, LockMode.None);
    }
    else {

        o = (BaseObject)GetSession().GetSessionImplementation().PersistenceContext.Unproxy(o);

        if (!inSession) {

            GetSession().Lock(type.ToString(), o, LockMode.None);
        }
    }
}

这是我的 IsInSession() 方法:

public virtual bool IsInSession() {

    ISession session = HibernateSessionManager.Instance.GetSession();

    var pers = session.GetSessionImplementation()
          .GetEntityPersister(GetType().ToString(), this);

    NHibernate.Engine.EntityKey key = new NHibernate.Engine.EntityKey(Id,
        pers, EntityMode.Poco);

    bool isInSession = false;

    try
    {
        object entity = session.GetSessionImplementation().PersistenceContext.GetEntity(key);

        if (entity != null)
        {
            isInSession = true;
        }
    }
    catch (NonUniqueObjectException) {}

    return isInSession;
}
4

1 回答 1

2

我确实看到您的其中一个映射中有lazy="false" ... NHibernate 默认使用延迟加载,因此我将从您的映射中删除所有lazy="false" 和lazy="true" 语句,然后继续使用 NHibernate 默认值。

我创建了以下 NUnit 测试并且两个测试都通过了,所以我无法复制你的问题,这意味着它要么是你的 lazy="false" 映射的东西,要么是其他一些问题......如果没有完整的诊断这些问题总是很困难应用在你面前...

使用以下测试用例,我能够创建以下错误:“正在初始化 [SampleApplication.Customer#19]-未能延迟初始化角色集合:SampleApplication.Customer.Addresses,没有会话或会话已关闭”

[Test]
public void Testing_A_Detached_Entity()
{
    // Arrange
    var sessionFactory = ObjectFactory.GetInstance<ISessionFactory>();

    Customer customer = null;

    using ( ISession session = sessionFactory.OpenSession() )
    {
        using ( ITransaction tx = session.BeginTransaction() )
        {
            customer = session.Query<Customer>()
                .Where( x => x.CustomerNbr == 19 )
                .FirstOrDefault();
        }
    }

    // Act
    TestDelegate actionToPerform = () =>
       {
           // Looping over this child collection should throw an Exception
           // because we no longer have an active NHibernate session
           foreach ( var address in customer.Addresses )
           {

           }
       };

    // Assert
    Assert.Throws<NHibernate.LazyInitializationException>( actionToPerform );
}

使用以下测试用例并使用 NHibernate 的 session.Lock() 方法,我能够成功地重新附加分离的对象并获得我的子集合的计数。

[Test]
public void Testing_Reattaching_A_Detached_Entity()
{
    // Arrange
    var sessionFactory = ObjectFactory.GetInstance<ISessionFactory>();

    Customer customer = null;

    using ( ISession session = sessionFactory.OpenSession() )
    {
        using ( ITransaction tx = session.BeginTransaction() )
        {
            customer = session.Query<Customer>()
                .Where( x => x.CustomerNbr == 19 )
                .FirstOrDefault();
        }
    }

    // Act
    ISession newSession = sessionFactory.OpenSession();

    newSession.Lock( customer, LockMode.None );

    // Assert
    Assert.That( customer.Addresses.Count > 0 );
}
于 2012-08-30T20:22:41.503 回答