NHibernate / MVC延迟加载失败,“会话已关闭或无会话”

时间:2011-05-31 22:46:21

标签: asp.net-mvc nhibernate

我在ASP.NET MVC应用程序后面使用NHibernate,在尝试通过AJAX调用保存对象时遇到了令人沮丧的问题。我很平常了:

无法懒惰地初始化角色集合:[type]没有会话或会话已关闭

问题是,据我所知,会话没有关闭。我正在使用HttpModule来处理每个请求模式的会话我的会话,NHibernate设置为使用 web current_session_context_class。这是HttpModule:

public class NHHttpModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.EndRequest += ApplicationEndRequest;
        context.BeginRequest += ApplicationBeginRequest;
    }

    public void ApplicationBeginRequest(object sender, EventArgs e)
    {
        CurrentSessionContext.Bind(SessionFactory.GetNewSession());
    }

    public void ApplicationEndRequest(object sender, EventArgs e)
    {
        var currentSession = CurrentSessionContext.Unbind(SessionFactory.GetSessionFactory());
        currentSession.Close();
        currentSession.Dispose();
    }

    public void Dispose()
    {
        // Do nothing
    }
}

我的SessionFactory也非常标准:

public static class SessionFactory
{
    private static ISessionFactory _sessionFactory;

    private static void Init()
    {
        _sessionFactory = Fluently.Configure() //Lots of other stuff here for NH config
            .BuildSessionFactory();
    }

    public static ISessionFactory GetSessionFactory()
    {
        if (_sessionFactory == null)
            Init();

        return _sessionFactory;
    }

    public static ISession GetNewSession()
    {
        return GetSessionFactory().OpenSession();
    }

    public static ISession GetCurrentSession()
    {
        return GetSessionFactory().GetCurrentSession();
    }
}

我正在使用一个工作单元进行交易,这就是我不在BeginRequest上打开交易的原因。即使这样,我也尝试过,结果没有变化。

我正在尝试通过AJAX帖子将Comment对象保存到User对象。这是控制器代码:

    [HttpPost, ValidateInput(false)]
    public ActionResult CreateCommentAsync(CommentCreateViewModel model)
    {
        if (!model.UserId.HasValue)
            return Content("false");

        var svc = DependencyResolver.Current.GetService<IPartnerUserService>();
        var user = svc.FindBy(model.UserId.Value, UserContext.Current.ActiveUser);

        // I put this in here as a test -- it throws the no-session error, too.            
        var count = user.Comments.Count();

        var comment = new Comment();
        comment.CommentText = model.CommentText;
        comment.DateCreated = DateTime.UtcNow;
        comment.CreatedBy = UserContext.Current.ActiveUser;

        // This is the original source of the error
        user.Comments.Add(comment);
        svc.Save(user, UserContext.Current.ActiveUser);

        return Content("true");
    }

我已经调试了应用程序并确认在请求开始时创建了一个会话,而且最令人困惑的是SessionFactory.GetCurrentSession().IsOpen为真,即使我在上面列出的错误中遇到了断点。

此外,当我渲染显示注释列表的视图时,会填充Comments列表 。我无法弄清楚当我添加它时失败的原因。

好像这还不够,每隔一段时间,代码没有变化,我得到错误并且可以成功添加评论。我把头发拉出来...有什么想法吗?这肯定是一个会话管理问题,但我已经完成了我在网上找到的所有内容以及所有帐户我正在进行会话管理的方式。有什么想法吗?

更新 我已经尝试了一些额外的测试,最值得注意的是当前会话是否具有我试图操纵的用户对象。确实如此。当我这样测试时:

if (!SessionFactory.GetCurrentSession().Contains(user))
    SessionFactory.GetCurrentSession().Refresh(user);

我在条件上得到true的结果。

评论者请求服务上的代码,但对于该特定呼叫,它不会触及会话,它只是验证请求用户是否具有权限,然后设置分离的条件。然后在该服务中调用存储库,这是代码:

public IEnumerable<T> FindBy(DetachedCriteria detachedCriteria) //Infrastructure.Querying.Query query)
{
    return detachedCriteria.GetExecutableCriteria(SessionFactory.GetCurrentSession()).Future<T>();
}

我认为这段代码不是问题的原因是它与详细信息视图中的代码完全相同。当我显示注释时,我没有任何延迟加载错误,并且我以相同的方式执行 - 我使用该服务加载用户对象,然后在列表中执行foreach迭代。我从来没有遇到过这样的问题。

如果这是AJAX调用的某种问题,我也将其更改为完整的回发,但仍然会出现相同的错误。

我不能为我的生活弄清楚这里发生了什么。

3 个答案:

答案 0 :(得分:1)

我终于发现了这个错误的原因,但只是运气不好。我会发布决议以防万一,但我无法提供任何解释为什么,并且可能会发布一个新问题,看看是否有人可以清空。

你会在我的代码中注意到我正在调用我的服务:

var user = svc.FindBy(model.UserId.Value, UserContext.Current.ActiveUser);

UserContext对象是一个静态类,其中包含一个会话存储的Current实例,该实例包含一个属性,该属性是当前用户记录的NHibernate对象。由于NHibernate代理属性的方式,UserContext.ActiveUser属性在被调用时必须执行类似的操作:

if (!SessionFactory.GetCurrentSession().Contains(ActiveUser))
    SessionFactory.GetCurrentSession().Refresh(ActiveUser);

出于某种原因,正是这个刷新过程搞砸了。当我显式检索活动用户而不是使用UserContext类时,一切正常。

我已经改变了我检索活动用户的方式,因此它没有使用会话存储的实例,而且工作正常。我希望我知道为什么,但我不知道!

答案 1 :(得分:0)

集合映射可能存在问题。您确定映射是否正确且实体是否已正确绑定?

检查一对多和多对一以及逆属性。

<强>更新

您是否尝试使用session.Lock(..)附加“user”实体?

我建议您尝试保存单个用户实体或单个评论实体,以测试问题是否来自评论收集。

答案 2 :(得分:0)

当您想要在视图中对会话执行某些操作时,也会抛出此异常 请检查此thread