I have two entities, a Shelf and a Product:
public class Shelf
{
public virtual IList<Product> Products { get; set; }
public Shelf()
{
Products = new List<Product>();
}
}
public class Product
{
public virtual string Name { get; set; }
}
Basically put, a Shelf can contain many Products, and a Product can be put on many Shelves. Thus, there’s a unidirectional many-to-many relationship between Shelf and Product. When I run the following code:
var shelf = new Shelf();
var product = new Product { Name = "Peas" };
shelf.Products.Add(product);
using (var session = SessionFactory.OpenSession())
{
session.Save(shelf);
}
NHibernate will save the Product and the Shelf, but it won’t save the relationship between them, so if you retrieve the Shelf, it will contain zero Products.
However, if I add a session.Flush() call, it will save the relationship correctly so that retrieving the Shelf will return one Product.
This blog post details my issue:
http://www.neeraj.name/2005/07/02/hibernate-session-close-does-not-call-session-flush.html
However, I was wondering why I need this session.Flush() call. It seems counter-intuitive that saving a Shelf with the right cascade behavior will save the Product, but fail to establish the relationship between the two unless I flush the session. It seems to me that a Save() call should save everything, and not just the entity themselves without their relationships.
Saveonly marks an entity to be persisted and generates an identifier. It doesn’t persist changes to the database.All changes (inserts, updates and deletes) are performed when flushing, which can occur in different moments.
However, transactions should also be used always. The correct workflow is (roughly):