发生异常后不要刷新会话 - NHibernate

时间:2009-11-30 10:36:30

标签: asp.net-mvc nhibernate azure

我正在开发.NET 3.5,NHibernate并托管在Windows Azure上的ASP.NET MVC Web应用程序。什么时候,webapp从本地开发结构运行,它工作正常。但是,当我将其移动到Windows Azure时,从MVC Web角色执行的每个插入都会以下面列出的异常结束。

知道我的NHibernate逻辑有什么问题吗? (可能是会话管理,不确定)

  

[AssertionFailure:Lokad.Translate.Entities.User条目中的null id(发生异常后不刷新会话)]      NHibernate.Event.Default.DefaultFlushEntityEventListener.CheckId(Object obj,IEntityPersister persister,Object id,EntityMode entityMode)+292      NHibernate.Event.Default.DefaultFlushEntityEventListener.GetValues(Object entity,EntityEntry entry,EntityMode entityMode,Boolean mightBeDirty,ISessionImplementor session)+93      NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent事件)+158      NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent事件)+469      NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent事件)+339      NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent事件)+85      NHibernate.Impl.SessionImpl.Flush()+ 275      NHibernate.Transaction.AdoTransaction.Commit()+236      Lokad.Translate.Repositories.PageRepository.Create(Page page)      Lokad.Translate.Controllers.PagesController.Create(Page page)      lambda_method(ExecutionScope,ControllerBase,Object [])+69      System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext,IDictionary 2 parameters) +251 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 2个参数)+31      System.Web.Mvc。<> c__DisplayClassa.b__7()+88      System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter过滤器,ActionExecutingContext preContext,Func 1 continuation) +534 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList 1个过滤器,ActionDescriptor actionDescriptor,IDictionary`2参数)+312      System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext,String actionName)+856      System.Web.Mvc.Controller.ExecuteCore()+ 185      System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext)+221      System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+ 586      System.Web.HttpApplication.ExecuteStep(IExecutionStep step,Boolean& completedSynchronously)+177

请注意,我使用的是_session.FlushMode = FlushMode.Commit;User用于自定义RoleProvider

public class SimpleRoleProvider : RoleProvider 
{
    readonly UserRepository Users = new UserRepository();

    public override string[] GetRolesForUser(string username)
    {
        try
        {
            var user = Users.Get(username);

            // no role if user is not registered
            if (null == user) return new string[0];

            // default role for registered user
            return user.IsManager ? new[] { "Manager", "User" } : new[] { "User" };
        }
        catch (Exception)
        {
            // role should not fail in case of DB issue.
            return new string[0];
        }
    }
}

3 个答案:

答案 0 :(得分:18)

在NHibernate事务中,你永远不应该捕获异常并忽略它们。

我试着解释原因。

例如,可能存在由数据库中的约束引起的异常。 (它也可能是由映射问题,属性或其他任何东西引发的异常引起的。)NHibernate尝试将内存中的状态与数据库同步。这是在提交时完成的 - 有时在查询之前完成,以确保对实际数据进行查询。当此同步失败时,数据库中的状态是随机的,某些更改会保留,而其他更改则不会。在这种情况下,你唯一能做的就是关闭会话。

请考虑代码中的决策和计算基于内存中的值。但是 - 如果忽略异常,这个值不是数据库中的值,它们永远不会存在。因此,您的逻辑将决定并计算“幻想数据”。

顺便说一下,抓住任何异常(无类型)并忽略它们绝不是一个好主意。您应该始终知道您处理的例外情况,并确保可以继续。

你在这里做的是吞咽编程错误。相信我,系统将不会更稳定。问题仅在于:您是否注意到错误发生时,或者您是否忽略错误,甚至将错误结果持久保存到数据库?当你执行后者时,当数据库不一致时,你不必感到惊讶,当你试图从数据库中获取数据时会出现其他错误。而且你永远不会找到导致错误的实际原因的代码。

答案 1 :(得分:4)

我终于找到了解决自己问题的方法。如果人们有兴趣,我会在这里发布解决方案。

public class SimpleRoleProvider : RoleProvider 
{
    // isolated session management for the RoleProvider to avoid
    // issues with automated management of session lifecycle.

    public override string[] GetRolesForUser(string username)
    {
        using (var session = GlobalSetup.SessionFactory.OpenSession())
        {
            var users = new UserRepository(session);
            var user = users.Get(username);

            // no role if user is not registered
            if (null == user) return new string[0];

            // default role for registered user
            return user.IsManager ? new[] {"Manager", "User"} : new[] {"User"};
        }
    }
}

基本上发生的事情是RoleProvider存储库似乎与常规的in-view / in-controller存储库没有相同的生命周期。因此,在调用RoleProvider时,NHibernate会话已被处理,导致上面观察到异常。

我已在上面用以下内容替换了代码。这个有自己的NHibernate会话管理,最终工作正常。

答案 2 :(得分:0)

如果您的列名包含保留字(例如,使用状态作为列名并且无法保存),则会发生此异常。