NHibernate, другой объект с тем же значением идентификатора уже был связан с сеансом - PullRequest
9 голосов
/ 13 марта 2012

Я работал с NHibernate, используя Fluent NHibernate для отображения. Я решил много вопросов и начал думать, что я опытный в nhibernate. Однако эта ошибка довольно странная.

Это моя модель:

    public class MessageNew
    {
        public virtual int Id { get; set; }
        public virtual string Content { get; set; }
        public virtual string Subject { get; set; }
        public virtual User User { get; set; }
        public virtual bool IsSent { get; set; }
        public virtual string AmazonMessageId { get; set; }
    }

И мое отображение

public class MessageNewMap : ClassMap<MessageNew>
{
    public MessageNewMap()
    {
        Id(x => x.Id);
        Map(x => x.Content).CustomSqlType("text");
        Map(x => x.Subject);
        Map(x => x.AmazonMessageId);
        Map(x => x.IsSent);

        References(x => x.User);
    }
}

Здесь, где возникает исключение:

foreach (var userToSend in usersToSend)
{
    string body = MailHelper.BuildSomeBody()
    if (userToSend  != CurrentUser)
    {
        MessageNew message = new MessageNew
        {
            User = userToSend,
            IsSent = false,
            Content = body,
            Subject = subject
        };
        session.Save(message); // Exception thrown
    }
}

Сведения об исключении:

NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 1779, of entity: Models.MessageNew
   at NHibernate.Engine.StatefulPersistenceContext.CheckUniqueness(EntityKey key, Object obj)
   at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
   at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
   at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
   at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
   at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
   at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
   at NHibernate.Impl.SessionImpl.Save(Object obj)

Генератор идентификаторов - это генератор идентификаторов с автоматическим приращением. (не хило или любой другой). Версия NHibernate - 3.2.0.

Я попытался перегрузить Equals и GetHashCode, не повезло.

Используемый мной шаблон UnitOfWork не требует фиксации транзакции или сброса сеанса внутри цикла foreach. NHibernate говорит, что есть другой объект с таким же идентификатором, но все, что я делаю, это вставляю новый объект, у которого вообще нет идентификатора.

Я использую одну и ту же структуру во всем проекте, и она хорошо работает везде, кроме этого. Я подозреваю, что это может быть связано со свойством «Content», которое является текстом и имеет большую строку.

Что мне здесь не хватает? Или в NHibernate чего-то не хватает?

Ответы [ 11 ]

4 голосов
/ 16 марта 2015

У меня была похожая проблема.Я прошел через множество дискуссий, учебных пособий и форумов, но после написания некоторых модульных тестов я понял:

1) session.Contains метод, работающий с экземплярами

2) session.Save/SaveorUpdateработает с идентификатором

Эта ошибка показывает, что у вас есть другие экземпляры объекта с таким же идентификатором в сеансе. Так, содержит возврат false, потому что вы работаете с разными экземплярами, а Save / SaveorUpdate выдает исключение, поскольку существует другой объект с таким жеID в сессии.Я решил свою проблему следующим образом (моя проблема была в Job Entity):

Job lJob = lSession.Load<Job>(this.ID);

if(lJob.ID==this.ID)
   lSession.Evict(lJob);

lSession.SaveOrUpdate(this);

Надеюсь, это поможет вам

4 голосов
/ 28 февраля 2014

Иногда это происходит, когда мы присваиваем объект тому же новому объекту. Поэтому сначала проверьте вашу модель и модель представления, чтобы они не были одинаковыми.

1 голос
/ 10 сентября 2013

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

1 голос
/ 13 марта 2012

Я прочитал код NH.Он в основном вставляет новый экземпляр в базу данных, чтобы получить его идентификатор.Затем он проверяет, является ли идентификатор, сгенерированный базой данных, действительно уникальным.Если нет, вы получите это исключение.

Ваша база данных не генерирует уникальные идентификаторы.Скорее всего, вы забыли установить его в столбце IDENTITY.

ИЛИ идентичность начинает рассчитывать на 0 вместо 1.

1 голос
/ 13 марта 2012

messagenew должен реализовывать Equals и GetHashCode

public class MessageNew
{
    public virtual int Id { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as MessageNew;
        return (other != null) && (IsTransient ? ReferenceEquals(this, other) : Id == other.Id;
    }

    private int? _cachedHashcode; // because Hashcode should not change
    public override int GetHashCode()
    {
        if (_cachedHashcode == null)
            _cachedHashcode = IsTransient ? base.GetHashCode() : Id.GetHashCode();

        return _cachedHashcode.Value;
    }

    public bool IsTransient { get { return Id == 0; } }
}
0 голосов
/ 30 мая 2017

Добавьте ниже двух строк перед Session.Save или Session.SaveOrUpdate

Session.Clear();
Session.Flush();

Это очистит все кэшированные объекты с Сессией.

0 голосов
/ 06 ноября 2014
     [..]
  };
  session.Clear();
  session.Save(message);

Попробуй, помог мне.

0 голосов
/ 11 декабря 2013

может быть немного поздно, но надеюсь, что это поможет.

У меня была похожая проблема, когда я пытался сохранить несколько экземпляров объекта в течение одного сеанса с автоматически сгенерированным столбцом на них. Моим решением было дать другое значение и назначить его вручную для каждой сущности, поэтому nhibernates не распознает его как один и тот же первичный ключ для этой сущности.

0 голосов
/ 13 марта 2012

Мое мнение: вы не объявляете генератор Id.Следовательно, как только вы получите два экземпляра MessageNew в сеансе, у них обоих будет 0 в качестве идентификатора.

0 голосов
/ 13 марта 2012

У вас уже есть другой экземпляр сущности с этим идентификатором.

Два возможных вопроса:

1 - Ваше сравнение сущностей не работает. Вы можете переопределить «равно» в соответствии с предложением или изменить свой тестовый пример, который вы использовали до сохранения:

if (userToSend.Id  != CurrentUser.Id)

2 - Вы не генерируете уникальный Id для своей сущности, вам нужно либо назначить Id самостоятельно, либо сгенерировать его с помощью NHibernate, либо сделать так, чтобы ваш sql-сервер сделал это за вас. В вашем отображении подразумевается, что следует использовать Identity (по умолчанию Fluents), но настроили ли вы столбец в вашей базе данных и столбец Identity?

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