tags:

views:

1522

answers:

2

I have a table Donations which has a CampaignID column that relates to the Campaigns Table. I need to insert a 0 in the CampaignID column instead of Null if the Campaign is not used for this Donation.

My mappings from the Donations table looks like this:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
    <class name="Donation,Entities" lazy="true" table="Donations" dynamic-update="true" >
     <id name="DonationID" column="PledgeID" type="Int64">
      <generator class="native" />
     </id>
     <many-to-one name="FundraisingCampaign" class="Campaign, Entities" column="CampaignID" lazy="proxy" not-found="ignore" cascade="none" />

Before I save to the Database I check to see if the Campaign Entity on my Donation Entity is null. If so then I set it to a new Campaign Entity and set the CampaignID = 0 like this.

    if (null == donation.FundraisingCampaign)
    {
        donation.FundraisingCampaign = new Campaign() {CampaignID = 0};
    }

The problem is that I get an ErrorMessage "object references an unsaved transient instance - save the transient instance before flushing." when trying to Save.

I don't understand why it cares about anything on my Campaign object other than the CampaignID because I have cascade="none" it should not try to save anything to the Campaign table.

I am forced by the current system to set a 0 there instead of Null as well so saving Null is not an option.

+2  A: 

Try loading the Campaign object whose DB identity is 0 from the DB. It will then be a fully persistent object. You should then be able to set it and persist the donation.

If this works, you need to change the ID property mapping of the Campaign object. Nh is unable to determine that your transient campaign object created here :

new Campaign() {CampaignID = 0};

is actually a detached object. What you should do is add an 'unsaved value' into your mapping of say, -1. Now Nh can tell the difference between your valid detached campaign with a DB identity Id of 0, and transient new campaigns with Ids of -1. Then remember to set the Id for newly created campaigns to -1.

Noel Kennedy
I set my unsaved-value to -1 and updated all my code to now set CampaignID to -1 in order to create a new one. I now have 0 in my CampaignID instead of Null. Thanks Noel.
Adam
Using a nullable had been easier.
Stefan Steinegger
+2  A: 
  1. NHibernate knows if an entity is already stored by checking the primary key. If it is 0, it is not stored. You can change this behavior in the mapping.
  2. If you try to save an entity, all the referencing entities must either cascade, or already be stored. This is important for NHibernate to take foreign keys. It can't point with the foreign key into you memory, it must be in the database, so it must be stored. If this is not the case, you get the exception message you have.

With this information you should understand why you have the problem.

Is the CampaignID generated with an automatic counter? Then it does not work anyway. (You can't set the id in the application.) Unless you store the Campaign with the CampaignID = 0 (see bellow).

You can make the CampaignID a nullable int, then the unsaved value is null by default.

Be aware that you get a Campaign with the CampaignID=0 in you database. This is a "Null Object". You need to store it, for instance after you setup the database.

If you want to avoid the null object, you get in troubles. NHibernate conceptually don't let you access the foreign keys, it manages it for you. You probably can do some tricks ( for instance in an interceptor), but I think it is not worth the troubles. You also have to make sure that there is no foreign key constraint, which is also not nice.

Stefan Steinegger