Reputation: 5055
I have a User object that as one of the properties contains a Photos property, which is am IList type.
The tables in the SQL database are joined by a foreign key. ie
Table User { userid long NOT NULL....... } Table UserPhoto { photoid long NOT NULL, userid long not null references [User].UserId........ }
So you cannot insert a row in userphoto without the corresponding User row.
What I want to be able to do is build up a User Object in code, add an Ilist of UserPhoto objects (which must neccesarily contain a blank user id, as does the User object as it hasn't been saved and created by identity insert yet)
My mappings are as follows
<class name="User" table="[User]">
<id name="UserId" column="Id">
<generator class="identity" />
</id>
<bag name="Photos" order-by="DisplayOrder asc" cascade="all">
<key column="UserId" />
<one-to-many class="UserPhoto" />
</bag>
</class>
<class name="UserPhoto" table="UserPhoto">
<id name="PhotoId" column="Id">
<generator class="identity" />
</id>
<property name="UserId" />
</class>
But when I try and save the User object with Nhibernate Session.Save(user), it throws an error saying Foreign key constraint failed. So im guessing its trying to insert either the user photos in the list before the user table, OR its not setting the newly generated user id property in the photos and trying to save them with a null user id.
Do you have to have something extra in the mapping to show that this is a foreign key column and what it applies to, so nhibernate knows how to insert the dependant rows in the right order so I can accomplish this in one insert?
Upvotes: 3
Views: 2310
Reputation: 26899
try this:
<class name="User" table="[User]">
<id name="UserId" column="Id">
<generator class="identity" />
</id>
<bag name="Photos" order-by="DisplayOrder asc" cascade="all" inverse="true">
<key column="UserId" />
<one-to-many class="UserPhoto" />
</bag>
</class>
<class name="UserPhoto" table="UserPhoto">
<id name="PhotoId" column="Id">
<generator class="identity" />
</id>
<many-to-one name="User" property-ref="UserId" column="UserId"/>
</class>
Inverse = true added to the Photos bag
http://bchavez.bitarmory.com/archive/2007/10/06/nhibernate-and-inversetruefalse-attribute.aspx
Also changed the UserId element to a many-to-one user element
Upvotes: 1
Reputation: 16393
You either need to add inverse="true" in the mapping for the Photo collection
<bag name="Photos" order-by="DisplayOrder asc" cascade="all" inverse="true">
or you will need to make the UserID column nullable in the Photo table.
If you do the first option, you need to configure the relationship between the objects yourself:
var user = new User();
var photo = new Photo();
photo.User = user;
user.Photos.Add(photo);
With inverse="true" set, NH will insert the user, update the userid based upon the identity value then insert each photo setting the userid in the photo table with each insert.
Without inverse="true" set, NH will insert the photos with a null userid, select all the photo ids for the inserted photos and then issue an update to set the userid after. This will result in an additional SQL statement being generated.
Upvotes: 0
Reputation: 6228
You need to add inverse="true"
to the bag, or else NHibernate will try to do an insert followed by an update:
<bag name="Photos" order-by="DisplayOrder asc" cascade="all" inverse="true">
<key column="UserId" />
<one-to-many class="UserPhoto" />
</bag>
Upvotes: 0