3

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?

3 Answers 3

1

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

Sign up to request clarification or add additional context in comments.

7 Comments

Ok thanks for the link, makes sense. Im still getting the error though, from the link you posted Im getting the impression I need a <many-to-one> mapping in the child declaration? If you see my UserPhoto declaration above Im just mapping UserId as a property. is this the problem? What do I need to do in the UserPhoto declaration to let it know about the FK relationship? I tried doing a plain Many to One on UserId but it said "An association from the table UserPhoto refers to an unmapped class: System.Int32"
If you use inverse=true, you need to manage the relationship both sides in code - see my answer for further details.
I've updated the answer. Try changing the property reference for UserId to a many-to-one user mapping and change the UserPhoto class to have
Does that mean I need a property called User of type User on the UserPhoto class? If I do it as above, I get the message "NHibernate.PropertynotFoundException : Could not find a getter for property 'User' in class"
Yes that is correct. Comment above should have said "and change the UserPhoto class to have a User property rather than a userID property"
|
0

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>

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.