0

I would love to thank @Stefan Steinegger and @David helped me out yesterday with many-to-many mapping.

I have 3 tables which are "News", "Tags" and "News_Tags" with Many-To-Many relationship and the "News_Tags" is the link table.

If I delete one of the news records, the following mappings will delete all my news records which have the same tags. One thing I need to notice, I only allowed unique tag stored in the "Tag" table.

This mapping make sense for me, it will delete the tag and related News records, but how can I implement a tagging system with NHibernate?

Can anyone give me some suggestion? Many thanks.

Daoming.

News Mapping:

<class name="New" table="News" lazy="false">
    <id name="NewID">
      <generator class="identity" />
    </id>
    <property name="Title" type="String"></property>
    <property name="Description" type="String"></property>

<set name="TagsList" table="New_Tags" lazy="false" inverse="true" cascade="all">
      <key column="NewID" />
      <many-to-many class="Tag" column="TagID" />
    </set>
</class>

Tag Mapping:

<class name="Tag" table="Tags" lazy="false">
    <id name="TagID">
    <generator class="identity" />
    </id>
    <property name="TagName" type="String"></property>
    <property name="DateCreated" type="DateTime"></property>

    <!--inverse="true" has been defined in the "News mapping"-->
    <set name="NewsList" table="New_Tags" lazy="false" cascade="all">
      <key column="TagID" />
      <many-to-many class="New" column="NewID" />
    </set>
</class>
Daoming Yang
  • 1,325
  • 3
  • 20
  • 41

3 Answers3

0

When I run into trouble like that, the first thing I twiddle with is the cascade option.

Ken
  • 1,066
  • 1
  • 10
  • 17
0

As far as I know, the mapping is correct (I'm using mapping files that look exactly the same). The problem is the cascade attribute: the "all" option forces NHibernate to propagate each action on an entity to the instances of the collection. In your case, when you delete a news item all related tags are deleted too.

You probably should use "none" (in that case you'll eventually end up with some unused tags in the database) or "delete-orphans" (on the news item side - use "none" on the tag side).

LorenzCK
  • 7,411
  • 2
  • 36
  • 28
  • Hi Lck, I have tried your suggestion and got the following errors: "object references an unsaved transient instance - save the transient instance before flushing." Any thoughts? – Daoming Yang Jan 05 '10 at 00:18
  • Yes, forgot about that. Since NHibernate isn't cascading updates to the collection, the Tag instances will not be updated. If you add a new tag to the collection, that instance will not be persisted and NHibernate will fail trying to create a link to it. The solution in this case is to manually SaveOrUpdate() each tag instance when you persist a news item. Kind of clunky, but it's a trade-off: other cascade settings persist entities automatically but can cause other issues. – LorenzCK Jan 05 '10 at 13:21
0

Use the cascade option "save-update".

The option "all" will cascade deletes, which you do not want in this case. But you the option "none" will require that the Tag entity is already persisted which I guess might not always be the case.

So by setting the cascade to "save-update" new Tags till be inserted in the Tags table and in the link table News_Tags, but when you remove a tag from a News entity it will only be removed from the link table not the Tags table.

Torkel
  • 3,364
  • 20
  • 16
  • Hi Torkel, I have tried your solution which to set the cascade="save-update" for news mapping and tag maping. It has two problem: 1. when I do news update including the tag updating. It did updates, but it did not remove the old tag from the link table; 2. When I try to delete the news it gave me the error: "deleted object would be re-saved by cascade (remove deleted object from associations)". I'm very confusing about this. Any other thoughts? – Daoming Yang Jan 05 '10 at 11:49