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

Joa*_*rel 8 nhibernate asp.net-mvc 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(对象实体,EntityEntry项,entityMode entityMode,布尔mightBeDirty,ISessionImplementor会话)+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.Controll ers.PagesController.Create(页面)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, IDictionary2 parameters)+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, IList1过滤器,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];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ger 18

在NHibernate事务期间,您永远不应该捕获异常并忽略它们.

我试着解释原因.

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

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

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

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


Joa*_*rel 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"};
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上发生的事情是,RoleProvider存储库似乎没有与常规视图内/控制器内存储库相同的生命周期。因此,在调用 RoleProvider 时,NHibernate 会话已被释放,从而导致上面观察到的异常。

我已将上面的代码替换为以下代码。这个有自己的 NHibernate 会话管理,并且最终工作正常。