如何避免NHibernate.NonUniqueObjectException

Jas*_*ile 8 nhibernate

我正在写一个博客引擎作为学习练习.我知道那里有很多博客引擎,但请耐心等待......

我有一个BlogPost实体,它有一个属性标签,它是与之关联的标签的IList.BlogPost.SetTags(string)方法拆分字符串,使用指定的标记名称创建新的Tag对象,并将它们添加到列表中.BlogPost.AddTag(字符串tagName)也是如此.

我想要发生的是,当我调用BlogPost.AddTag("foo"),其中一个名为"foo"的标签实体已经存在并且在数据库中持久存在时,nHibernate只是意识到这一点,并用现有标签连接帖子.

在BlogRepository.Save()方法中,我检查标签列表中的每个标签是否已经存在.如果没有,我通过调用TagRepository.Save(tag)保存它;

问题是,在下面的示例代码中,我收到一个错误"NHibernate.NonUniqueObjectException:具有相同标识符值的另一个对象已经与会话关联:标记1,实体:CMS.Core.Model.Tag"当我尝试使用现有标记持久保存BlogPost对象时.当我坚持只使用新标签的BlogPost对象时,它们就被创建了,一切都很好.

注意我还使用TagName作为bp_Tags表的数据库中的主键.当表只存储唯一的Tag名称时,使用整数或GUID PK似乎是多余的.

我的nHibernate配置如下:

  <class name="CMS.Core.Model.Tag,CMS.Core" table="bp_Tags">
    <id column="TagName" name="TagName" type="String" unsaved-value="">
      <generator class="assigned" />
    </id>
  </class>

  <class name="CMS.Core.Model.BlogPost,CMS.Core" table="bp_Content">
    <id name="Id" column="Id" type="Int32" unsaved-value="0">
      <generator class="native"></generator>
    </id>
    <property name="SubmittedBy" column="SubmittedBy" type="string" length="256" not-null="true" />
    <property name="SubmittedDate" column="SubmittedDate" type="datetime" not-null="true" />
    <property name="PublishDate" column="PublishDate" type="datetime" not-null="true" />
    ...    
    <bag name="_tagsList" table="bp_Tags_Mappings" lazy="false" cascade="all">
      <key column="Target_Id" />
      <many-to-many class="CMS.Core.Model.Tag,CMS.Core" column="TagName" lazy="false" />
    </bag>
Run Code Online (Sandbox Code Playgroud)

NHibernate.NonUniqueObjectException:具有相同标识符值的不同对象已与会话关联:标记1,实体:Bariliant.CMS.Core.Model.Tag

    BlogPost post, post2;

    using (UnitOfWork.Start())
    {  
        post = BlogPostFactory.CreateBlogPost("test post", "test body");
        post.Publish();
        BlogRepository.Save(post);
        UnitOfWork.Current.Flush();

        post.SetTags("tag 1, tag 2");
        BlogRepository.Save(post);
        UnitOfWork.Current.Flush();
    }

    using (UnitOfWork.Start())
    {
        post2 = BlogPostFactory.CreateBlogPost("test post2", "test body");
        post2.Publish();
        BlogRepository.Save(post2);
        UnitOfWork.Current.Flush();

        post2.AddTag("tag 1");
        BlogRepository.Save(post2);  // throws
Run Code Online (Sandbox Code Playgroud)

...

关于我做错了什么以及如何解决它的任何想法?

Dan*_*ger 8

由于TagName是ID,因此您正在运行NHibernate的身份映射.它的身份映射已经知道具有相同ID的对象,因此它会为您提供该异常.

您可能想要尝试一些内容,以查看该会话中是否已存在该标记,如果存在,则将该现有标记与第二篇文章相关联.

Psuedo-code示例:

var tag = session.Get<Tag>("Tag 1");

if (tag != null)
{
   post.AddTag(tag);
}
else
{
   post.AddTag(new Tag("Tag 1"));
}
Run Code Online (Sandbox Code Playgroud)

此博客文章将为您提供详细说明: NHibernate - 跨会话操作