1

使用 NHibernate 和 C#,我在删除使用属性延迟加载加载的对象时遇到问题。

对象是。

public class Item
{
    public virtual Guid ItemID { get; set; }    
    public virtual string Name { get; set; }
    public virtual decimal Price { get; set; }
    public virtual string Image { get; set; }
    public virtual Iesi.Collections.Generic.ISet<Tax> Taxes { get; set; }
}

“税收”集合在这里加载了延迟加载。所以我需要保持会话开放(据我所知)。加载“项目”对象时,我使用以下查询。

    public Item FindByID(Guid itemID)
    {
        //using(var session = NHibernateHelper.OpenSession())
        //using (var tr = session.BeginTransaction())
        //{
        //    return session.Get<Item>(itemID);
        //}

        var session = NHibernateHelper.OpenSession();
        return session.Get<Item>(itemID);
    }

在上面的代码中,FindByID()您可以看到我已经注释掉了一些在从数据库中获取对象后关闭会话的代码。这是因为,我需要打开会话,因为我有Taxes对象集合可以被懒惰地访问。打开代码部分显示返回找到的对象后会话仍然打开。

不,当我使用上面加载的对象使用以下代码执行删除时。

    public void RemoveItem(Item item)
    {            
        using(var session = NHibernateHelper.OpenSession())
        using (var tr = session.BeginTransaction())
        {
            try
            {
                session.Delete(item);
                tr.Commit();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }
    }

我收到以下错误..

非法尝试将集合与两个打开的会话相关联

错误很明显,获取的对象已打开会话,当我打开另一个会话以删除同一对象时,会产生此错误。

请有人指导我摆脱这个错误。谢谢。

4

3 回答 3

3

错误在您的设计中。您正在打开一个会话以获取该对象,并使其保持打开状态。然后您正在打开另一个会话以删除托管对象,但您打算自动关闭此会话。那么为什么不关闭FindByID方法中的会话呢?

您需要考虑您的设计,因为上述内容不一致 - 或者如 Morten 所说,提出更深入的问题(即应该如何设计)。

由于您需要访问惰性实例,因此最好使用 Morten 的方法并使用每个 Web 请求的会话或设置您自己的包含会话的请求上下文(如果您不创建 Web 应用程序)。如果您还没有基于上下文的设计,一种更简单的方法是在事件开始时创建会话(即用户想要删除项目)并将会话传递给 DAO 方法:

public Item FindByID(Session session, Guid itemID)
{
    using (var tr = session.BeginTransaction())
    {
        return session.Get<Item>(itemID);
    }
}

public void RemoveItem(Session session, Item item)
{
    using (var tr = session.BeginTransaction())
    {
         session.Delete(item);
         tr.Commit();
    }
}

您可以更进一步,并在 DAO 之外创建事务,这样会更快并充分利用事务(即稍后您可能会收到通过通用 DAO 执行相互依赖的数据库操作的请求)。

于 2013-01-02T10:35:28.680 回答
1

您需要确保始终只有一个会话处于活动状态。有两种流行的方法:

  • 拥有一个您始终将请求转发到的服务层。该服务层负责会话处理(和事务处理)。所有业务逻辑都必须在会话层中处理,因此您始终拥有会话。您必须在 UI 中加载所需的所有内容并将其作为响应的一部分返回。有关使用 nhibernate 的简单请求响应服务层,请参见例如http://davybrion.github.com/Agatha/
  • 每个 Web 请求都有一个会话。这通常涉及在调用控制器方法之前打开会话(和事务),然后提交事务。通常这是通过使用您放在需要会话的方法上的属性来处理的。我无法给出一个完整的例子,但我知道NHibernate 3.0 Cookbook中描述了一种流行的方法。
于 2013-01-02T10:41:52.230 回答
0

假设您在 Web 应用程序中使用 session-per-request 模式,最简单的解决方案是修改NHibernateHelper.OpenSession方法以返回请求的当前会话。为了完成这项工作,您不能将会话访问包装在一个using块中,而是在 global.asax 中管理会话生命周期。

I would take this approach if you have a lot of existing code that you don't want to refactor. If you have the time to refactor then you should use dependency inject to inject the ISession into your repository/query objects.

于 2013-01-02T14:28:47.780 回答