NHibernate FecthMode.Eager:没有懒惰地初始化集合,没有关闭会话或会话

时间:2012-08-08 08:20:44

标签: c#-4.0 nhibernate

我从一个MVC3应用程序调用的WCF项目开始使用NHibernate。 一切似乎都没问题,但为了优化数据库上的请求我想使用FecthMode.Eager,但是在集合上我收到了这个错误:

  

未能懒惰地初始化集合,没有会话或会话关闭

以下是我的WCF服务的代码(简化):
映射:
Statement.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="MyWCFNameSpace.Domain" namespace="MyWCFNameSpace.Contract" xmlns="urn:nhibernate-mapping-2.2">
    <class name="StatementInfo" table="STATEMENT" lazy="false" >
        <id name="NumStatement" column="NUM_STATEMENT">
            <generator class="identity" />
        </id>
        <property name="TypeStatement">
            <column name="TYPE_STATEMENT" sql-type="VARCHAR2" not-null="false" />
        </property>
        <one-to-one name="AddressStatement" class="AddressStatementInfo" cascade="all" />
        <bag name="NHBlocList" inverse="true" cascade="all">
            <key>
                <column name="NUM_STATEMENT" />
            </key>
            <one-to-many class="BlocInfo" />
        </bag>
    </class>
</hibernate-mapping>

Address.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="MyWCFNameSpace.Domain" namespace="MyWCFNameSpace.Contract" xmlns="urn:nhibernate-mapping-2.2">
    <class name="AddressInfo" table="ADDRESS" lazy="false" >
        <id name="NumStatement" column="NUM_STATEMENT">
            <generator class="identity" />
        </id>
        <property name="LineAdresse1">
            <column name="LINE_ADDRESS_1" sql-type="VARCHAR2" not-null="false" />
        </property>
        <property name="LineAdresse2">
            <column name="LINE_ADDRESS_2" sql-type="VARCHAR2" not-null="false" />
        </property>
        <property name="Country">
            <column name="COUNTRY" sql-type="VARCHAR2" not-null="false" />
        </property>
    </class>
</hibernate-mapping>

Bloc.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="MyWCFNameSpace.Domain" namespace="MyWCFNameSpace.Contract" xmlns="urn:nhibernate-mapping-2.2">
    <class name="BlocInfo" table="BLOC" lazy="false" >
        <composite-id>
            <key-property name="NumStatement" column="NUM_STATEMENT" />
            <key-property name="NumBloc" column="NUM_BLOC" />
        </composite-id>
        <property name="BlocType">
            <column name="BLOC_TYPE" sql-type="VARCHAR2" not-null="false" />
        </property>
    </class>
</hibernate-mapping>

DAO代码:
StatementDao.cs

[Repository]
public class StatmentDao : HibernateDao, IStatmentDao
{
    public StatmentDao() { }

    //...

    [Transaction]
    public StatmentInfo GetStatment(string numStatment)
    {
        return (StatmentInfo)CurrentSession.CreateCriteria<StatmentInfo>()
            .SetFetchMode("Address", global::NHibernate.FetchMode.Eager)
            .SetFetchMode("NHBlocList", global::NHibernate.FetchMode.Eager)
            .Add(Restrictions.Eq("NumStatment", numStatment))
            .UniqueResult();            
    }

服务类:

public class MyWCFServiceImpl : MyWCFService
{
    public IStatementDao StatementDao { get; set; }

    public override GetStatementResponse GetStatement(GetStatementRequest request)
    {
        if (request == null || string.IsNullOrEmpty(request.NumStatement))
            return null;

        GetStatementResponse response = new GetStatementResponse();

        response.Statement = StatementDao.GetStatement(request.NumStatement);

        return response;
    }

和测试课

[TestFixture]
public class GetStatementTest : AbstractIntegrationTests
{
    private IApplicationContext ctx;

    public IMyWCFService MyWCFService { get; set; }

    [SetUp]
    public void InitContext()
    {
        // Configure Spring programmatically
        ctx = ContextRegistry.GetContext();
    }

    [Test]
    public void GetStatement()
    {
        MyWCFService = (IMyWCFService)ctx.GetObject("myWCFService");
        GetStatementResponse response;

        response = EmissaireGUService.GetStatement(
            new GetStatementRequest()
            {
                NumStatement = "STATEMENT_1",
            });

       // Asserts...
    }

如果没有FetchMode.Eager,nhibernate会生成3个请求:

SELECT ... FROM STATEMENT this_ WHERE this_.NUM_STATEMENT = :p0
SELECT ... FROM ADDRESS address10_ WHERE address10.NUM_STATEMENT = :p0
SELECT ... FROM BLOC nhbloclist0_ WHERE bloclist0_.NUM_RELEVE=:p0

这对表演来说并不好(我的真实代码是最复杂的,我得到了20个请求)。这就是我尝试使用FetchMode.Eager只生成一个请求的原因。

在地址上使用FetchMode.Eager我现在只有2个请求:

SELECT ... FROM STATEMENT this_ left outer join ADDRESS address10_ on this_.NUM_STATEMENT =address10_.NUM_STATEMENT WHERE this_.NUM_STATEMENT = :p0
SELECT ... FROM BLOC nhbloclist0_ WHERE bloclist0_.NUM_RELEVE=:p0

对我来说这是一个好的开始,但是当我尝试在blocs集合上做同样的事情时,我得到了懒惰的初始化异常。

我试图在任何地方设置lazy = false,但我没有得到任何结果。 在问我在互联网上进行了一些挖掘之前,但我没有找到太多(在我的理解水平上),除非可能是会议的问题太早关闭,但我不知道如何解决这个问题。

至少先谢谢你指出正确的方向。

0 个答案:

没有答案