2012-04-27 75 views
0

我有一个C#.Net Web服务。我正在调用一个使用nHibernate连接到我的数据库的dll(C#.Net)。当我调用dll时,它会执行对数据库的查询并加载父对象“任务”。然而,当DLL试图访问子对象“Task.SubTasks”,它引发以下错误:Web服务nHibernate SessionFactory问题

NHibernate.HibernateException failed to lazily initialize a collection of role: SubTasks no session or session was closed 

我是新来NHibernate的所以不知道什么我失踪一段代码。

在调用dll之前,我需要在Web服务中启动Factory会话吗?如果是这样,我该怎么做?

编辑:添加了Web服务代码和CreateContainer()方法代码。此代码被调用的dll之前,为了所谓的

[WebMethod] 
    public byte[] GetTaskSubtask (string subtaskId) 
    { 
     var container = CreateContainer(windsorPath); 

     IoC.Initialize(container); 
     //DLL CALL 
     byte[] theDoc = CommonExport.GetSubtaskDocument(subtaskId); 

     return theDoc; 

    } 

/// <summary> 
/// Register the IoC container. 
/// </summary> 
/// <param name="aWindsorConfig">The path to the windsor configuration 
/// file.</param> 
/// <returns>An initialized container.</returns> 
protected override IWindsorContainer CreateContainer(
    string aWindsorConfig) 
{ 
    //This method is a workaround. This method should not be overridden. 
    //This method is overridden because the CreateContainer(string) method 
    //in UnitOfWorkApplication instantiates a RhinoContainer instance that 
    //has a dependency on Binsor. At the time of writing this the Mammoth 
    //application did not have the libraries needed to resolve the Binsor 
    //dependency. 

    IWindsorContainer container = new RhinoContainer(); 

    container.Register(
     Component.For<IUnitOfWorkFactory>().ImplementedBy 
      <NHibernateUnitOfWorkFactory>()); 
    return container; 
} 

编辑:添加DLL的代码和库代码...

DLL的代码

public static byte[] GetSubtaskDocument(string subtaskId) 
{ 
    BOESubtask task = taskRepo.FindBOESubtaskById(Guid.Parse(subtaskId)); 

    foreach(subtask st in task.Subtasks) <--this is the line that throws the error 
    { 
    //do some work 
    } 


} 

库任务

/// <summary> 
/// Queries the database for the Subtasks whose ID matches the 
/// passed in ID. 
/// </summary> 
/// <param name="aTaskId">The ID to find matching Subtasks 
/// for.</param> 
/// <returns>The Subtasks whose ID matches the passed in 
/// ID (or null).</returns> 
public Task FindTaskById(Guid aTaskId) 
{ 
    var task = new Task(); 
    using (UnitOfWork.Start()) 
    { 
     task = FindOne(DetachedCriteria.For<Task>() 
        .Add(Restrictions.Eq("Id", aTaskId))); 
     UnitOfWork.Current.Flush(); 
    } 
    return task; 
} 

子任务知识库

/// <summary> 
/// Queries the database for the Subtasks whose ID matches the 
/// passed in ID. 
/// </summary> 
/// <param name="aBOESubtaskId">The ID to find matching Subtasks 
/// for.</param> 
/// <returns>The Subtasks whose ID matches the passed in 
/// ID (or null).</returns> 
public Subtask FindBOESubtaskById(Guid aSubtaskId) 
{ 
    var subtask = new Subtask(); 
    using (UnitOfWork.Start()) 
    { 
     subtask = FindOne(DetachedCriteria.For<Subtask>() 
        .Add(Restrictions.Eq("Id", aSubtaskId))); 
     UnitOfWork.Current.Flush(); 
    } 
    return subtask; 
} 

回答

1

您已明显将启用延迟加载(或更好:未禁用,因为它是默认行为)的NHibernate数据类中的一个集合映射到其中一个。 NHibernate加载实体并为映射集合创建一个代理。只要他们被访问,NHibernate尝试加载该集合的项目。但是如果你在这之前关闭你的N​​Hibernate会话,你会收到错误。您可能通过Web服务将您的数据对象展示给Web服务客户端。在序列化过程中,XmlSerializer尝试序列化提示NHibernate填充它的集合。会话关闭时发生错误。

两种方法可以防止此:

  • 关闭响应发送

  • 禁用延迟加载您的收藏后的会话,让他们立即被加载

在上述编辑之后添加:

在您的存储库中,您在using语句中启动UnitsOfWork。代码完成后即将处理。我不知道UnitOfWork的实现,但我认为它控制着NHibernate会话的生命周期。通过部署UnitOfWork,你的probalby关闭NHibernate会话。当您的映射初始化延迟加载的集合时,这些集合尚未填充且发生错误。 NHibernate需要加载实体来填充延迟初始化集合的会话的确切实例。

如果您使用延迟加载并且有一个在响应完成之前关闭会话的存储库,您将遇到类似问题。一种选择是在请求开始时初始化UnitOfWork,并在响应完成后将其关闭(例如,在Application.BeginRequest,Global.asax.cs中的Application_EndRequest中)。这当然意味着将您的资源库紧密集成到Web服务中。

在任何情况下,结合延迟加载为单个请求创建会话是一个坏主意,并且很可能在将来创建类似的问题。如果您无法更改存储库实现,则可能必须禁用延迟加载。

+0

感谢您的意见。但是,我认为我的问题处于更高层次。我没有任何nHibernate会话代码。我使用温莎打开一个容器,但不是一个会话。引发错误的代码是在dll中。 Web服务初始化容器,然后调用dll。 dll从db获取对象并将它们作为byte []返回给Web服务,但在它到达之前它正在进行barfing。 – MikeTWebb 2012-04-27 17:05:17

+0

但在某个地方有人正在打开和关闭NHibernate会话。由于错误指出NHibernate抱怨一个封闭的会话,它一定是由某人打开和关闭的。温莎的哪些部分在使用? ActiveRecord,WCF工具,NHibernate集成? – 2012-04-27 17:11:40

+0

表示同意......它在某处“自动”发生。这是nHibernate集成。 hibernate.cfg有一个部分。我已经在上面添加了CreateContainer代码 – MikeTWebb 2012-04-27 17:27:37

0

使用加兰的反馈我解决了这个问题。我删除从DLL库中的UnitOfWork(S)代码和包裹Web服务调用在以下的UnitOfWork见代码MODS的DLL:在DLL

Web服务

[WebMethod] 
public byte[] GetSubtaskDocument (string subtaskId) 
{ 
    var container = CreateContainer(windsorString); 

    IoC.Initialize(container); 

    byte[] theDoc; 
    using (UnitOfWork.Start()) 
    { 
     //DLL call 
     theDoc = CommonExport.GetSubtaskDocument(subtaskId); 
     UnitOfWork.Current.Flush(); 
    } 
    return theDoc; 
} 

库调用

public Subtask FindSubtaskById(Guid aSubtaskId) 
{ 
    return FindOne(DetachedCriteria.For<Subtask>() 
       .Add(Restrictions.Eq("Id", aSubtaskId))); 
}