NHibernate doesn't delete db record when object is set to null? - nhibernate

I have two classes: Family and Address.
A family has a physical address and a mailing address.
The mapping file for Family looks like:
....
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<many-to-one name="PhysicalAddress" class="Address" column="PhysicalAddressId" cascade="all" unique="true" />
<many-to-one name="MailingAddress" class="Address" column="MailingAddressId" cascade="all" unique="true" />
...
The mapping file for Address looks like:
...
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="StreetAddress1" column="StreetAddress1" />
<property name="StreetAddress2" column="StreetAddress2"/>
<property name="City" column="City" />
<property name="State" column="State" />
<property name="ZipCode" column="ZipCode" />
...
(Note that Family-PhysicalAddress and Family-MailingAddress are one-to-one relationships.)
What I would like to happen is that when I execute
aFamily.MailingAddress = null;
session.Save(aFamily);
session.Flush();
I expect NHibernate to automatically delete the mailing address record from SQL Server for me.
BUT, that doesn't happen. NHibernate does not delete the address record from SQL Server.
Is there any way I can make it work?
Thank you!

This behaviour isn't supported by NHibernate. Of course the problem is that you probably don't have access to the NHibernate session in your domain logic where the change is made.
One possible -- though admittedly not ideal solution -- is to simply run another process to clean up orphaned entities.
Here is a discussion of this scenario:
http://colinjack.blogspot.com/2008/03/nhibernate-gotchas-orphans-and-one-to.html
And a link to a ticket on the issue:
https://nhibernate.jira.com/browse/NH-1262

Unfortunately NHibernate currently does not support automatic deletions of orhphans for many-to-one (Hibernate v3 in Java does support it). It is only supported on lists (cascade="all-delete-orphan").
What you can try to do is to use component mapping. Maybe it is possible to embed many-to-one into a component.
But I think it would better to explicitly delete the related object.

Related

NHibernate with Second Level Cache Not Rehydrating Properties Marked insert="false" update="false"?

Having trouble with implementing second level cache in Nhibernate. I have a class mapped as follows:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Data" namespace="Data">
<class name="Account" table="Accounts" lazy="false">
<cache region="Standard" usage="read-write" include="all"/>
<id column="ID" name="ID">
<generator class="assigned" />
</id>
<version name="VersionStamp" column="VersionStamp" type="integer" unsaved-value="0" />
<property name="Name" not-null="true" />
<property name="Type" not-null="true" />
<property name="ClientID" not-null="true" insert="false" update="false" />
<property name="DateCreated" not-null="true" type="UtcDateTime" />
<property name="LastUpdatedDate" not-null="true" type="UtcDateTime" />
<property name="IsActive" not-null="true" />
<many-to-one name="Client" class="Client" column="ClientID" not-found="exception" not-null="true" />
</class>
</hibernate-mapping>
The property "ClientID" is a foreign key into the Clients table and the Client many-to-one property uses it to look up the associated client object.
When I add a new Account, I look up the Client object from the database with a Session.Get and assign it to my Account object's Client property. Behind the scenes, this also automatically populates the ClientID property when the object is written to the database, and the ID is correctly stored in the database. When I retrieve the Account object from the database by ID using Session.Get, all the fields are populated correctly when the object is retrieved.
However, when I implement the second level cache using the settings shown above, the ClientID property is NOT populated when the Account object is retrieved using Session.Get, but the Client property is populated correctly. Is there some reason why this will not work with second level cache? Or have I done something wrong in my mapping/configuration?
For now I am just using SysCache as my caching provider, and both query and second level cache are turned on. The Client class mapping contains a corresponding one-to-many property for the Accounts.
I like the convenience of having the ClientID property on my Account class, so that I can read it without using the Client property, and it seems to work fine without caching.
Thanks for any help.
Rich
I tried to reproduce your situation locally. With your mapping (used the same as the snippet above) I was able to get incorrect behaviour only on UPDATE. In that case, the ClientID was cached, and while the Client reference was changed, the ClientID remained unchanged. In other cases caching was working as expected.
The solution is to change the mapping. The below suggested mapping is the most suitable for read-only properties like ClientID. (I am using that approach as well).
<property name="ClientID" formula="[ClientId]"
not-null="true" insert="false" update="false" />
So the trick is in the formula mapping instead of Column (the default when none is provided)

how to move from poid to hilo in nhibernate

I have been having a lot of trouble with deadlocks. I've received some really useful feedback that suggested this may be a side effect of my use of identity which is a regular id. My application is of reasonable size. 20-30 entities. Making a major change like this is quite a scary proposition. So would be very grateful for some feedback
1) what would i need to do to change to hilo. This application has quite a lot of data. Would i need to do some kind of data migration.
2) is hilo the correct choice, would guid be an easier upgrade.
An example entity mapping. I'm using nhibernate 2
<class name="Post" table="Post">
<id name="Id" type="Int32" column="Id" unsaved-value="0">
<generator class="identity"/>
</id>
<many-to-one name="Company" column="CompanyId" class="EStore.Domain.Model.Company, EStore.Domain" />
<many-to-one name="Retailer" column="RetailerId" class="EStore.Domain.Model.Retailer, EStore.Domain" />
<many-to-one name="Parent" column="ParentId" class="EStore.Domain.Model.Post, EStore.Domain" />
<many-to-one name="PostStatus" column="PostStatusId" class="EStore.Domain.Model.PostStatus, EStore.Domain" />
</class>
highlow needs a source for high (table or sequence) and calculates a lowvalue.
you need a sequence/table which value * maxlowvalue(the value you define in the mapping) is greater than the highest id in your database/table(if you give each table a different highvalue sequence/table)

Lazy load nhibernate one-to-one

I have a true one to one mapping. But I would like to use lazy loading(load on demand).
I have Class Person with a association with Class Address. The mapping looks like this..
PERSON
<one-to-one name="address" class="Person" cascade="all-delete-orphan" access="field">
ADDRESS
<class name="Address" table="Address" lazy="true">
<id name="id" column="addressId" type="Int32" access="field">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<one-to-one name="person" class="Address" constrained="true" access="field" />
Does anyone see something wrong with this? How do I enable proxy/lazy loading for address?
Thanks
Heres a good discussion on the topic http://ayende.com/Blog/archive/2007/05/10/NHibernate-onetoone.aspx
Crucial quote: "In other words, one-to-one cannot be lazily loaded, which is one of the reasons why it is recommended to use two many-to-one instead."
Also see https://www.hibernate.org/162.html and NHibernate: how to enable lazy loading on one-to-one mapping

Odd save behaviour with NHibernate and Rhino Repositories

I am experiencing some odd behaviour with NHibernate. I'm retrieving a list of Learners from a repository, updating them as necessary, the odd thing is when I save the first one, the changes made to all the learners are being commited to the database.
[Transaction]
public void UpdateLearner(Learner learner)
{
//UnitOfWork.CurrentSession.Save(learner);
}
Any ideas why? I dont have caching enabled. I know its something to do with the transaction as the changes get persisted even with the call to the save method commented out.
This is my mapping:
<class name="Learner" table="ILR_Learner">
<id name="Id" column="ILRLearnerID">
<generator class="native" />
</id>
<property column="LastWarning" name="LastWarning" type="DateTime" />
<property column="Submitted" name="SuccessfulSubmission" type="DateTime" />
<join table="vwLearnerLSCUpload">
<key column="ILRLearnerID" foreign-key="ILRLearnerID"/>
<property column="Dog" type="DateTime" name="Dog"/>
</join>
<join table="Learner">
<key column="Id" foreign-key="ILRLearnerID"/>
<property column="Food" name="Food" type="String" length="20" />
</join>
</class>
When updating entities, changes are tracked automatically. So when the transaction is committed all changed entities are persisted. No need to call:
Session.Save(entity);
See this Question.
To disable change tracking per entity you have to evict the entity from the session:
Session.Evict(entity);
To persist any changes, you would then call:
Session.Update(entity);

Use two joined subclasses in nhibernate

Ok, new to nhibernate and I am working on a project that has already fully implemented it.
Scenerio: One class (Person) has two joined subclasses (RoleA and RoleB).
What I need is that a given person can actually be both in RoleA and RoleB. How, when given a person that is already created and in RoleA, can I then make them also in RoleB while maintaining the relationships with RoleA?
So, you have something like the following (with Students and Teachers taking the place of RoleA and RoleB):
<class name="Person" table="Persons" >
<id name="Id" column="PersonID">
<generator class="native" />
</id>
<property name="Name" column="Name" not-null="true" />
<joined-subclass name="Student" table="Students">
<key column="PersonID" />
<property name="Grade" column="Grade" not-null="true" />
</joined-subclass>
<joined-subclass name="Teacher" table="Teachers">
<key column="PersonID" />
<property name="ClassName" column="ClassName" not-null="true" />
</joined-subclass>
</class>
If that is the case, your best bet is to use a one-to-one mapping to accomplish the same thing. Here is a good reference: http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-onetoone
This person had a similar problem as you, and ended up going with the one-to-one mapping option:
http://groups.google.com/group/nhusers/browse_thread/thread/1d83e0cd3c2bf58f