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
Pingback: NHibernate foreign key is null when saving | Jisku.com - Developers Network