Ioannis Panagopoulos blog

Tutorials on HTML5, Javascript, WinRT and .NET

NHibernate inverse="true" and cascade="save-update" demo

by Ioannis Panagopoulos

 

We will work with the following database schema:

The corresponding domain model is as follows:

Entity.cs

public class Entity
{
 private long _iD;
 public virtual long ID
 {
     get { return _iD; }
     set { _iD = value;}
 }
 
 private string _description;
 public virtual string Description
 {
     get { return _description; }
     set { _description = value;}
 }
 
 private IList<Detail> _details;
 public virtual IList<Detail> Details
 {
     get { return _details; }
     set { _details = value; }
 }
(...)
Detail.cs
public class Detail:INotifyPropertyChanged,IEditableObject
{
    private long _iD;
    public virtual long ID
    {
        get { return _iD; }
        set { _iD = value; }
    }
 
    private string _line1;
    public virtual string Line1
    {
        get { return _line1; }
        set { _line1 = value; }
    }
 
    private string _line2;
    public virtual string Line2
    {
        get { return _line2; }
        set { _line2 = value; }
    }
 
    private Entity _relatedEntity;
    public virtual Entity RelatedEntity
    {
        get { return _relatedEntity; }
        set { _relatedEntity = value; }
    }
(...)

The first mapping file to be tested defines the association from both sides as follows:

Entity.hbm.xml
<bag name="Details" table="Details" cascade="save-update">
       <key column="EntityID"/>
       <one-to-many class="NHibernateTests.Detail,NHibernateTests"/>
</bag>
Detail.hbm.xml
<many-to-one name="RelatedEntity" column="EntityID" access="field.camelcase-underscore" cascade="save-update"/>

We instantiate a new Entity. We add two new Detail domain objects in the Details list and leave their “RelatedEntity” property to null. When we save the Entity domain object the following SQL is generated by NHibernate:

INSERT INTO Entities (Description) VALUES (@p0); select SCOPE_IDENTITY(); @p0 = 'Dokimi'
INSERT INTO Details (Line1, Line2, EntityID) VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY(); @p0 = 'Test1', @p1 = 'Test1', @p2 = ''
INSERT INTO Details (Line1, Line2, EntityID) VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY(); @p0 = 'Test2', @p1 = 'Test2', @p2 = ''
UPDATE Details SET EntityID = @p0 WHERE ID = @p1; @p0 = '16', @p1 = '33'
UPDATE Details SET EntityID = @p0 WHERE ID = @p1; @p0 = '16', @p1 = '34'
 
That is, NHibernate inserted the Detail domain objects and updated their EntityID column (the update was due to their inclusion in the Details list in the Entity Domain model since their RelatedEntity property was not set).
Now we also set the “RelatedEntity” for the Detail Domain Objects. When we save the Entity the following SQL is generated by NHibernate:
INSERT INTO Entities (Description) VALUES (@p0); select SCOPE_IDENTITY(); @p0 = 'Dokimi'
INSERT INTO Details (Line1, Line2, EntityID) VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY(); @p0 = 'Test1', @p1 = 'Test1', @p2 = '17'
INSERT INTO Details (Line1, Line2, EntityID) VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY(); @p0 = 'Test2', @p1 = 'Test2', @p2 = '17'
UPDATE Details SET EntityID = @p0 WHERE ID = @p1; @p0 = '17', @p1 = '35'
UPDATE Details SET EntityID = @p0 WHERE ID = @p1; @p0 = '17', @p1 = '36'
 
Note that now, the UPDATE SQL is not needed since the information about the relation (EntityID column) has already been set in the INSERT statements (due to the fact that the RelatedEntity property was set). In order to omit this we can set inverse=”true” as follows:
Entity.hbm.xml
<bagname="Details"table="Details"cascade="save-update" inverse="true">
       <keycolumn="EntityID"/>
       <one-to-manyclass="NHibernateTests.Detail,NHibernateTests"/>
</bag>
We run the same example as before and now:
INSERT INTO Entities (Description) VALUES (@p0); select SCOPE_IDENTITY(); @p0 = 'Dokimi'
INSERT INTO Details (Line1, Line2, EntityID) VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY(); @p0 = 'Test1', @p1 = 'Test1', @p2 = '17'
INSERT INTO Details (Line1, Line2, EntityID) VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY(); @p0 = 'Test2', @p1 = 'Test2', @p2 = '17'
That is, inverse=”true” has caused the UPDATE SQL statements to be omitted (although the cascade has added the appropriate detail records).

 

kick it on DotNetKicks.com

Shout it
blog comments powered by Disqus
hire me