Не сбрасывать сеанс после возникновения исключения - NHibernate - PullRequest
8 голосов
/ 30 ноября 2009

Я занимаюсь разработкой веб-приложения ASP.NET MVC под .NET 3.5, NHibernate и размещен на Windows Azure. Когда веб-приложение запускается из локальной среды разработки, оно работает нормально. Тем не менее, когда я перемещаю его в Windows Azure, каждая вставка, выполняемая из веб-роли MVC, заканчивается исключением, перечисленным ниже.

Есть идеи, что не так с моей логикой NHibernate? (может быть управление сессией, не уверен)

[AssertionFailure: нулевой идентификатор в записи Lokad.Translate.Entities.User (не сбрасывать сеанс после возникновения исключения)] NHibernate.Event.Default.DefaultFlushEntityEventListener.CheckId (объект obj, IEntityPersister persister, идентификатор объекта, 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 (Страница страницы) Lokad.Translate.Controllers.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, IDictionary 2 параметра) +31 System.Web.Mvc. <> C__DisplayClassa.b__7 () +88 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter (фильтр IActionFilter, preContext ActionExecutingContext, фильтры Func 1 continuation) +534 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList 1, дескриптор 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, логическое и завершено синхронно) + 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 ]

18 голосов
/ 30 ноября 2009

Вы никогда не должны перехватывать исключения и игнорировать их во время транзакции NHibernate.

Я пытаюсь объяснить, почему.

Могут быть исключения, например, вызванные ограничениями в базе данных. (это также может быть вызвано проблемами отображения, исключениями, вызванными свойствами или чем-то еще.) NHibernate пытается синхронизировать состояние в памяти с базой данных. Это делается при фиксации, а иногда перед запросами, чтобы убедиться, что запросы выполняются на реальных данных. Когда эта синхронизация завершается неудачно, состояние в базе данных является случайным , некоторые изменения сохраняются, другие нет. Единственное, что вы можете сделать в этом случае, это закрыть сеанс.

Учтите, что решения и вычисления в вашем коде основаны на значениях в памяти . Но - в случае игнорируемого исключения эти значения не являются значениями в базе данных, они никогда не будут там. Таким образом, ваша логика будет определять и рассчитывать на «фэнтези-данные».

Кстати, никогда не стоит ловить какие-либо исключения (нетипизированные) и игнорировать их . Вы всегда должны знать, какие исключения вы обрабатываете, и быть уверенным, что вы можете продолжить.

То, что вы здесь делаете, - глотание ошибок программирования. Поверьте, система не будет более стабильной. Вопрос только в том, замечаете ли вы ошибку, когда она возникает, или игнорируете ее там и даже сохраняете результат ошибки в базе данных ? Когда вы делаете последнее, вам не нужно удивляться, когда ваша база данных несовместима, и возникает другая ошибка, когда вы пытаетесь получить данные из базы данных. И вы никогда не найдете код, который является действительной причиной ошибки.

4 голосов
/ 01 декабря 2009

Я наконец нашел решение своей проблемы. На случай, если людям будет интересно, я выкладываю решение здесь.

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, и в итоге он работает нормально.

0 голосов
/ 12 апреля 2012

Это исключение может возникнуть, если имена столбцов содержат зарезервированные слова (например, используйте статус в качестве имени столбца, и сохранить его будет невозможно)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...