DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Designing a Blog Application Using Document Databases
  • Relational DB Migration to S3 Data Lake Via AWS DMS, Part I
  • NoSQL for Relational Minds
  • Business Logic Database Agent

Trending

  • How the Go Runtime Preempts Goroutines for Efficient Concurrency
  • Why We Still Struggle With Manual Test Execution in 2025
  • Simplify Authorization in Ruby on Rails With the Power of Pundit Gem
  • Scalability 101: How to Build, Measure, and Improve It
  1. DZone
  2. Data Engineering
  3. Databases
  4. Playing with NHibernate - Inverse and Cascade Mapping Attributes

Playing with NHibernate - Inverse and Cascade Mapping Attributes

I have to admit that NHibernate provides a really flexible way of handling class inheritance and parent-child relationship.

By 
Mariano Vazquez user avatar
Mariano Vazquez
·
Jul. 12, 13 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
35.8K Views

Join the DZone community and get the full member experience.

Join For Free

Although I'm a big fan of Entity Framework, I have to admit that NHibernate provides a really flexible way of handling class inheritance and parent-child relationship. That said, I've noticed that these two important concepts are not very well explained in the documentation, which leads to a several discussions and debates in the community about the proper way of mapping your tables (and sometimes to explanations that state the opposite).

Consider the explanation of the inverse mapping (taken from theNHibernate docs):

Inverse: (optional - defaults to false) mark this collection as the "inverse" end of a bidirectional association.

If you think this explanation is incomplete, that makes two of us. There are some examples of the concept in the docs, but I couldn't find one that fully explains what this concept means and how you can use it together with thecascade (another mapping attribute). In the next few lines, I'm going to (try to) do this.

Scenario - One-to-many relationship

Let's define a simple scenario in which you have Products and Categories. And one Category can have many Products (i.e. a one-to-many relationship). In this case, the Database diagram and the model classes should look similar to this:

Database diagram

Model classes

Basic mapping (default values)

Next, we are going to create mappings for these classes. Let's start with the default mapping values, just to see how NHibernate behaves as is:

Basic mapping

We are going to run a simple test case that creates a Category with 3 Products and saves everything in the DB. For this, we are setting theProduct.Category property of each product before saving the data. Notice that we need to do everything ourselves: we have to associate the Category on each Product and we also have to save each entity in the session separately (and in a specific order, as we will be see later):

Note: you can find the solution with all the test cases here.

Basic mapping - Using Product.Category

As you can see in the image above, NHibernate generates the expected SQL statements (3 INSERTS). But there is an important caveat on this approach: you need to make sure that you're saving the entities in the right order. If you save the Products in the session before saving the Category, when committing the transaction NHibernate will behave as follows:

  • First, it will execute an INSERT statement for each Product, setting NULL in the CategoryId (which will only work if this column is nullable).
  • Then, it will execute an INSERT statement to save the Category.
  • Finally, it will execute an UPDATE statement for each Product to set the newly generated CategoryId.

Usually you should try to avoid doing things on your own, like saving the entities in the session in the right order or associating each Product with its Category individually (that's why we use an ORM in the first place, right?). To make things easier, NHibernate can handle this. In the next few lines we'll to remove some of our repetitive code by taking advantage of theInverse and Cascade mapping attributes.

Setting Inverse to 'false' (default)

Let's analyze the way we are associating the Products with the Category. I know that some folks will prefer to add the 3 Products inside theCategory.Products collection instead of setting the Category on each individual Product. What if I tell you that with the current mapping you can use both approaches? This is because we set the Inverse attribute in theCategory.Products mapping to false (default value). So what Inverse does? It tells NHibernate that the Parent is responsible (or not) of saving the association to its childs. The inverse=false mapping means that when you save the Category you will also save the association of each Product that is inside the Category.Products collection. In constrast, setting this value to true basically means that "the Parent does not have the responsibility of saving the association".

Check the following code. Notice that instead of setting theProduct.Category property we are now adding the Product to theCategory.Products collection (and it works!):

Basic mapping - Using Category.Products

Although we've reduced the code a little bit, there are two problems with this approach (if we use the current mapping):

  1. To save the association, NHibernate will use an INSERT/UPDATE strategy for each Product (same as before), which won't work if we have a null constraint on the Product.CategoryId column.
  2. Inverse can be used only to save entity association info, not data. Hence, we still need to save each item individually. If we save only the Category (the Parent), NHibernate will throw the followingTransientObjectException:

Basic mapping - Saving the Category only will throw an exception

A way to improve this approach is by setting the Cascade mapping attribute to a value different than 'none' (default). And that's what we are going to do in the next section.

Setting Cascade mapping attribute

mapping means that when you save the Category you will also save the association of each Product that is inside the Category.Productscollection. In constrast, setting this value to true basically means that "the Parent does not have the responsibility of saving the association". TheCascade mapping attribute helps NHibernate to decide which operations should be cascaded from the Parent object to the Child object. Collections mapped with a value different than 'none' will perform extra tasks in addition to saving the entity. For instance, you can set the collection withcascade=save-update, which means that when the object is saved/updated, NHibernate will check the associations and save/update any object that require it (for a complete explanation of all cascade values go here)

Let's update the mappings of the Category class by setting the cascadevalue to all:

Cascade mapping - Setting cascade mapping attribute

Now, we can safely remove the code that saves the products individually. By only saving the Category in the session will be enough since now we've instructed NHibernate to save the products "in cascade".

Cascade mapping - Setting cascade mapping attribute

Again, NHibernate will use the INSERT/UPDATE technique, which means that this approach won't work if the Product.CategoryId column is not-nullable.

Setting Inverse to 'true'

If you are facing the 'not-nullable' scenario, consider changing the Inverseproperty to true. Which means that the Category is no longer responsible to manage of the relationship. Then, update your code to associate the Products and the Categories using the Products.Category property (because the Product class is now the only owner of the association). Finally, you only need to save the Category in session (as before).

Cascade-Inverse mapping - Setting cascade and inverse mapping attributes

Summary

To sum up what we've explained:

  • The Inverse attribute tells NHibernate if the collection is responsible to manage the relationship. inverse=false means that it should update the relationship, while inverse=true means that 'it does not have to do anything'.
  • The Cascade attribute helps NHibernate to decide which operations should be cascaded from the parent object to the child object. For instance, cascade=save-update tells NHibernate that when the Parent is saved/updated, it also needs to needs to insert the Parent's childs.
  • Depending on the scenario you should decide which value to use on these two properties. For instance:
    • (one-to-many scenario) If your foreign-key allows nullable values, you can use a collection with inverse=false and a cascade value different than 'none'. When you save the Parent, NHibernate will take care of saving both childs and association.
    • (one-to-many scenario) If you have a not-nullable constraint in the DB, you can use a collection with inverse=true and a cascade value different than 'none'. In this case, you'll only need to associate the child with its parent in code before saving the parent.

Database NHibernate Attribute (computing) Relational database

Published at DZone with permission of Mariano Vazquez, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Designing a Blog Application Using Document Databases
  • Relational DB Migration to S3 Data Lake Via AWS DMS, Part I
  • NoSQL for Relational Minds
  • Business Logic Database Agent

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!