NHibernate: неожиданная ошибка сеанса при сохранении объекта - PullRequest
2 голосов
/ 31 марта 2011

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

Мне трудно описать мою проблему безчтобы быть точным, я просто буду использовать метафоры Article и Category.

public class Article
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Category Category { get; set; }
}
public class Category
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    public override string ToString() { return "cat-" + this.Id.ToString(); }
}
public class ArticleMapping : ClassMap<Article>
{
    public ArticleMapping()
    {
        this.Id( x => x.Id, "id" ).GeneratedBy.Assigned();
        this.Map( x => x.Name, "name" );
        this.References( x => x.Category ).Fetch.Join().Cascade.None();
    }
}
public class CategoryMapping : ClassMap<Category>
{
    public CategoryMapping()
    {
        this.ReadOnly();
        this.Id(x => x.Id, "id").GeneratedBy.Assigned();
        this.Map(x => x.Name, "name");
    }
}

Я создаю новую Article , присваиваю ей имя, присваиваю Категория из списка, загруженного с помощью метода, описанного ниже, и попытка сохранения.

Я получаю следующее предупреждение:

Невозможно определить, соответствует ли cat-1 назначенному идентификаторувременно или отдельно

Если вы посмотрите на модель и код отображения, вы увидите, что cat-1 вообще не должен сохраняться - это категория и она определена только для чтения и не является каскадной..

//code that loads the list of categories
IStatelessSession session = this.SessionService.GetStatelessSession();
IList<Category> cats = session.CreateCriteria<Category>().List<Category>();
this.SessionService.EndSession(session);

//code that's called to save the instance
ISession session = this.SessionService.GetSession();
using (ITransaction transaction = session.BeginTransaction())
{
  session.SaveOrUpdate(article);
  transaction.Commit();
}
this.SessionService.EndSession(session);

Если я снова вызываю метод Save, все становится банановидным:

Исключение:

NHibernate.StaleStateException: неожиданная строка сонет: 0;ожидается: 1

Stacktrace:

в NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched (Int32 rowCount, инструкция IDbCommand) в NHibernate.AdoNet.NonBatchingBatcher.AddToBatch (ожидание IExpectation)

в NHibernate.Persister.Entity.AbstractEntityPersister.Update (идентификатор объекта, поля Object [], Object [] oldFields, объект rowId, Boolean [] includeProperty, Int32 j, объект oldVersion, Objectobj, SqlCommandInfo sql, сеанс ISessionImplementor)

в NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert (идентификатор объекта, поля Object [], Object [] oldFields, Object rowId, Boolean [] includeProperty, Int32 j,oldVersion, Object obj, SqlCommandInfo sql, сеанс ISessionImplementor)

в NHibernate.Persister.Entity.AbstractEntityPersister.Update (идентификатор объекта, поля Object [], Int32 [] dirtyFieldA исключение первого шанса типа 'NHibernate.StaleStateпроизошло в NHibernate.dll с, Boolean hasDirtyCollection, Object [] oldFields, Object oldVersion, Object obj, Object rowId, сеанс ISessionImplementor)

в NHibernate.Action.EntityUpdateAction.Execute ()

в NHibernate.Engine.ActionQueue.Execute (Исполняемый файл IExecutable)

в NHibernate.Engine.ActionQueue.ExecuteActions (список IList)

в NHibernate.Engine.ActionQueue.ExecuteActions ()

в NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions (сеанс IEventSource)

Раньше я думал, что NHibernate свободен от черной магии, но из-за этого я хочу посетить моего священника-вуду, чтобы попросить помощи у другого царства ...

У кого-нибудь есть идеи, откуда исходит StaleStateException?Где я ошибся в этот раз?

Заранее спасибо

Себи

Ответы [ 2 ]

2 голосов
/ 31 марта 2011

не уверен, но проблема может заключаться в том, что вы загружаете объект, используя один сеанс, и обновляете его, используя другой.
В этом сценарии объект действительно отсоединен.
попробуйте использовать Bind(), чтобы привязать объект ко второму сеансу или рассмотреть возможность использования только одного сеанса (обратите внимание, что сеанс! = соединение с БД. То есть открытие сеанса не должно быть слишком дорогим, и это неплохая идея).

1 голос
/ 01 апреля 2011

Тьфу! Иногда это помогает проверить все локальные вещи перед тем, как выкрикивать их в мир ... Был где-то триггер базы данных, который переписал идентификатор, полученный NHibernate из последовательности.

Значение:

  • Предупреждение было полностью понятным, как категория, присвоенная статья не имела состояния сеанса, так что должен быть определен через выборку или в качестве альтернативы session.Refresh (), который имеет тот же результат.

  • Исключение StaleObjectStateException должно было происходят, так как ряд постоянный, не может быть расположен в стол (спасибо, мистер Триггер!)

Извините, что беспокою вас ...

...