NHibernate,具有相同标识符值的不同对象已与会话关联

Sad*_*ran 9 nhibernate fluent-nhibernate

我一直在使用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; }
    }
Run Code Online (Sandbox Code Playgroud)

和我的映射

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生异常:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

例外细节:

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)
Run Code Online (Sandbox Code Playgroud)

Id生成器是数据库驱动的自动递增id生成器.(不是hilo或任何其他).NHibernate版本是3.2.0.

我试过重载Equals和GetHashCode,没有运气.

我正在使用的UnitOfWork模式不需要在foreach循环中提交事务或刷新会话.NHibernate说有另一个具有相同id的对象,但我所做的只是插入一个新对象,它根本没有任何标识符.

我在我的项目中使用相同的结构,除了这个之外,它在任何地方都运行良好.我怀疑它可能是因为"Content"属性,它是文本并设置为一个大字符串.

我在这里失踪了什么?或NHibernate缺少什么?

Fer*_*ery 5

我有类似的问题。我经历了很多讨论、教程和论坛,但在编写了一些单元测试之后,我意识到:

1) session.Contains 方法适用于实例

2)session.Save/SaveorUpdate与ID一起使用

此错误表明您在会话中有另一个具有相同 ID 的对象实例。因此,包含返回 false,因为您正在处理不同的实例,并且 Save/SaveorUpdate 会抛出异常,因为会话中存在另一个具有相同 ID 的对象。我已经这样解决了我的问题(我的问题是在工作实体中):

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

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

lSession.SaveOrUpdate(this);
Run Code Online (Sandbox Code Playgroud)

我希望它能帮助你


Fir*_*iro 1

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; } }
}
Run Code Online (Sandbox Code Playgroud)