NHibernate 3 (Part 7) One-To-Many with Inverse

Previous Post
Next Post

The previous example had a problem: it use one INSERT AND one UPDATE for each chapter. In this post, I use an alternative way to mapping a one-to-many list, using the inverse attribute. As usual, the code is at my AjCodeKata Code Project, under trunk/NHibernate/BookChapters. You can download a “frozen” version from NHibernate3BookChaptersInverse.zip.

I modified the previous solution, adding a new Books.Inverse console project, copying the original Books.Console. And I added a new attribute in Book mapping:

<list name="Chapters" cascade="all-delete-orphan" 
  inverse="true">
  <key column="BookId"/>
  <index column="ChapterIndex"/>
  <one-to-many class="Chapter"/>
</list>

The new attribute is inverse=”true”. With this clue, NHibernate knows that the management of the list and its items are under programmer control. What does it mean? I ran the new console program: each chapter is saved with only ONE insert, but the result in the database was:

No BookId, no ChapterIndex were set! The problem is in the code:

cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings" });
cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema" });
cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions" });

When I created a new Chapter, I didn’t set any Book or Chapter Index information. With inverse=”true”, now that is my responsibility. Then, I changed the Chapter class, adding a new property:

// Used in Inverse example
public virtual int ChapterIndex { get; set; }

And I changed the chapter creation code to:

cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings", Book = cookbook, ChapterIndex = 0 });
cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema", Book = cookbook, ChapterIndex = 1 });
cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions", Book = cookbook, ChapterIndex = 2 });

Now, the output of the insert is:

NHibernate: INSERT INTO Books (Title, Author, Id) VALUES (@p0, @p1, @p2);@p0 = 
'NHibernate Cookbook' [Type: String (4000)], @p1 = 'Jason Dentler' 
[Type: String (4000)], @p2 = b643aa0e-1917-4066-96a4-64a09562a58a [Type: Guid (0)]

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Models and Mappings' [Type: String (4000)], @p1 
 = NULL [Type: String (4000)], @p2 = b643aa0e-1917-4066-96a4-64a09562a58a
 [Type : Guid (0)], @p3 = 0 [Type: Int32 (0)], @p4 = 
 df9114af-7183-4b1b-9826-d12982a898a5 [Type: Guid (0)]
 
NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Configuration and Schema' 
 [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 =
 b643aa0e-1917-4066-96a4-64a09562a58a [Type: Guid (0)], @p3 = 1 [Type: Int32 (0)],
 @p4 = 3fc1df36-c7de-4ff8-add2-8f843b627115 [Type: Guid (0)]

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Sessions and Transactions' 
 [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 = 
 b643aa0e-1917-4066-96a4-64a09562a58a  [Type: Guid (0)], @p3 = 2 [Type: Int32 (0)],
 @p4 = 9c8891e4-6419-4469-aa3a-154f2c908985 [Type: Guid (0)]

Chapters are saved as:

All Ok! Note that I have not to add the chapters to the NHibernate session: they are saved as part of the saved book. But after inverse=true, I should set the inverse relation (Chapter to Book) and order properties.

Next steps: explore deletion, update, more complex mapping, logging options, alternative mappings (Fluent NHibernate, ConfORM, new NHibernate 3.2 mapping by code).

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

1 thought on “NHibernate 3 (Part 7) One-To-Many with Inverse

  1. Pingback: NHibernate foreign key is null when saving | Jisku.com - Developers Network

Leave a comment