Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate: mapping bidirectional one-to-many with IList semantics

Here are the relevant pieces. This is a parent object:

public class Article
{
    public virtual IList<ArticleRevision> Revisions { get; set; }
}

<list name="Revisions" cascade="all" inverse="true" table="ArticleRevision">
  <cache usage="read-write" />

  <key column="ArticleID" not-null="true" />
  <index column="Number" type="int32" />
  <one-to-many class="ArticleRevision" />
</list>

This is a child:

public class ArticleRevision
{
    public virtual Article Article { get; set; }
}

<many-to-one name="Article" column="ArticleID" not-null="true" />

Now, I create an instance of Article, add one ArticleRevision to Article.Revisions collection, set ArticleRevision.Article to reference the Article instance and shove it to the database:

INSERT 
INTO
    ArticleRevision
    (Content, Keywords, CreatedAt, SiteID, ArticleID, CreatedByUserID, ID) 
VALUES
    (@p0, @p1, @p2, @p3, @p4, @p5, @p6);

No Number column gets inserted.

How do I correctly map a bidirectional one-to-many collection with list semantics in NHibernate?

like image 795
Anton Gogolev Avatar asked May 11 '11 16:05

Anton Gogolev


2 Answers

From the NHibernate documentation:

Please note that NHibernate does not support bidirectional one-to-many associations with an indexed collection (list, map or array) as the "many" end, you have to use a set or bag mapping.

like image 187
cremor Avatar answered Sep 27 '22 01:09

cremor


As far as I know, All of ORM frameworks state that when you have a bi-directional relationship, you should define one side, in which your ORM will rely on when updating the state of your bi-directional relationship. Otherwise, you can get side effects such as

  • Inconsistent mapping
  • Violation of constraints
  • Among other stuffs

In your case, the column ArticleID can be managed by both ends of the relationship. Because of that, you should mark one side as inverse="true", which should be placed in the many side when you have a @OneToMany relationship.

However, you can achieve the same behavior by disabling the property ArticleRevision.Article, by setting its mapping as

<many-to-one name="Article" column="ArticleID" insert="false" update="false" />

Using insert="false" update="false", you are saying: NHibernate, does not care about me, in which, as a result, NHibenate you simply ignore it. Now, discard inverse="false" in the property Article.Revisions, and you will get your answer.

UPDATE:

Remove not-null="true" from your key column because it is updated right after ArticleRevision. As a consequence, you will get a constraint violation otherwise.

like image 36
Arthur Ronald Avatar answered Sep 24 '22 01:09

Arthur Ronald