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

NHibernate,具有相同标识符值的不同对象已与会话关联,nhibernate,fluent-nhibernate,Nhibernate,Fluent Nhibernate,我一直在与NHibernate合作,使用Fluent NHibernate进行映射。我解决了很多问题,并开始认为自己在nhibernate方面很有经验。 然而,这个错误很奇怪 这是我的模型: public class MessageNew { public virtual int Id { get; set; } public virtual string Content { get; set; } public virtual s

我一直在与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);
    }
}
例外情况详情:

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)
Id生成器是数据库驱动的自动增量Id生成器。(不是hilo或任何其他人)NHibernate版本是3.2.0。

我尝试过重载Equals和GetHashCode,但没有成功

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

我在我的项目中使用了相同的结构,除了这个,它在任何地方都能很好地工作。我怀疑这可能是因为“Content”属性,即文本并设置为大字符串


我错过了什么?或者NHibernate缺少什么?

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; } }
}

该异常通常表示您在同一会话中尝试管理的对象有两个具有相同标识符值的独立实例。

您已经有另一个具有该id的实体实例

两个可能的问题:

1-您对实体的比较不起作用。您可以按照建议重写equals,也可以在保存之前更改您使用的测试用例:

if (userToSend.Id  != CurrentUser.Id)

2-您没有为实体生成唯一的Id,您需要自己分配Id,让NHibernate生成一个Id,或者让sql server为您完成。在您的映射中,这意味着应该使用标识(Fluents默认设置),但您是否已将数据库中的列设置为“是”和“标识”列?

我阅读了一些NH代码。它基本上是将新实例插入数据库以获取其id。然后检查数据库生成的id是否确实是唯一的。如果不是,则会出现此异常

您的数据库未生成唯一ID。您很可能忘记将其设置为标识列


或者标识开始依赖于0而不是1。

我的目标:您没有声明Id生成器。因此,一旦您在会话中获得两个MessageNew实例,它们的Id都将为0。

您可以使用
execit()
从会话中逐出对象,然后您可以执行任何您想要的操作。
如果在另一个会话中有相同的对象,则会发生此错误。

可能有点晚,但希望这能有所帮助


当我试图在同一个会话中保存一个对象的多个实例时,遇到了一个类似的问题,其中包含一个自动生成的列。我的解决方案是给每个实体一个不同的值,然后手动分配给每个实体,所以nhibernates不会将其识别为该实体的相同主键

有时,当我们将对象分配给同一个新对象时,会发生这种情况。因此,首先检查模型和viewmodel是否不相同

     [..]
  };
  session.Clear();
  session.Save(message);

试试这个,帮了我。

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

1) Contains方法用于实例

2) session.Save/SaveorUpdate与ID一起工作

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

Job lJob=lSession.Load(this.ID);
if(lJob.ID==this.ID)
lSession.驱逐(lJob);
lSession.SaveOrUpdate(此);

我希望它能帮助您

会话之前添加以下两行。保存
会话。保存或更新

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

这将清除会话中的所有缓存实体。

在映射中,您有
ClassMap
但显示类
消息
这是一个输入错误吗?是的,实际上是“MessageNew”。感谢您的警告,我编辑了这篇文章。我想知道是否有一个FluentNH约定正在应用,它将生成器更改为“已分配”。该列是一个标识列,其中Auto increment设置为true。谢谢你的提示,但这不是我的案例,身份种子是1,不是0?谢谢你的回复。该异常并非源自该行(用户比较)。if(userToSend!=CurrentUser)只是业务逻辑。在将消息保存到会话的位置引发异常。第二:该列是identity列,我需要数据库生成的ID,所以我没有放置ID生成器。此外,Id的创建很好,没有问题,但是,默认配置是Identity Id Generator,我在整个项目中都使用它,不仅仅是这个模型。它工作正常。谢谢你的提示。我确实重写了,但没有成功:(欢迎使用StackOverflow。请记住,通过链接到支持其简洁性的文档页面,简短/简单的答案总是可以得到加强。您可能想更详细地了解一下。只有两行代码和一个“试试这个”并不是真正的答案。
Job lJob = lSession.Load<Job>(this.ID);

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

lSession.SaveOrUpdate(this);
Session.Clear();
Session.Flush();