I'm writing a blog engine as a learning exercise. I know there are plenty of blog engines out there, but bear with me...
I have a BlogPost entity that has a property Tags that is an IList of tags associated with it. The BlogPost.SetTags(string) method splits the string, creates new Tag objects with the specified tag name, and adds them to the list. Same for BlogPost.AddTag(string tagName).
What I would like to have happen is that when I call BlogPost.AddTag("foo") where a tag entity named "foo" already exists and is persisted in the database, nHibernate just realizes that and wires up the post with the existing tag.
In the BlogRepository.Save() method, I check to see if each tag in the Tags list already exists. If not, I Save it with a call to TagRepository.Save(tag);
The problem is, in the sample code below, I'm getting an error "NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: tag 1, of entity: CMS.Core.Model.Tag" when I try to persist a BlogPost object using an existing tag. When I persist a BlogPost object that only uses new tags, they're created and everything is fine.
Note I'm also using the TagName as the primary key in the database for the bp_Tags table. It seemed superfluous to use an integer or GUID PK when the table only stores unique Tag names.
My nHibernate configuration looks like:
<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>
NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: tag 1, of entity: 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
...
Any thoughts on what I'm doing wrong and how to fix it?