I have a basic structure. A User object and a UserDetails object. The User table has the identity primary key to generate the UserId, and then I want to also save a UserDetails object for this UserId. Doing this separately this would be easy, but I’m trying to find a way if I can do it in one go, as the User class contains a reference to the UserDetails object. eg
User u = new User() { Name=”me”, Age=17, UserDetails = new UserDetails() { Detail1 = 1 } };
So all I have to do is pass around the user object, which then contains object based references to other related sub-information (I have simplified it greatly for this example but there are several more similar classes as UserDetails, like UserMatchConfiguration etc and a lot of fields for each one)
I want to be able to build up the object in code, or to have it passed around and modified, then to call save on the parent User object, and for it to then save all related objects. I have achieved this so far using one-to-one mappings and save cascades, but the problem is when you create a new object, the UserId is set to zero for all related classes when I want it to save the User class first, then to propogate the generated UserId to all the related classes and then save them.
Mapping is as follows so far.
<class name="User" table="[User]">
<id name="UserId" unsaved-value="0">
<generator class="identity" />
</id>
<property name="FirstName" />
<property name="LastName" />
<property name="EmailAddress" />
<property name="DateOfBirth" />
<property name="Gender" />
<property name="PostcodePartOne" />
<property name="PostcodePartTwo" />
<many-to-one name="UserLocation" column="UserLocationId" />
<property name="DateJoined" />
<property name="LastLoggedOn" />
<property name="Status"/>
<property name="StatusNotes" />
<bag name="Photos" order-by="DisplayOrder asc" inverse="true" lazy="false" cascade="all">
<key column="UserId" />
<one-to-many class="UserPhoto" />
</bag>
<bag name="Interests" inverse="true" lazy="false" cascade="all">
<key column="UserId" />
<one-to-many class="UserMatchInterest" />
</bag>
<bag name="Preferences" inverse="true" lazy="false" cascade="all">
<key column="UserId" />
<one-to-many class="UserPreference" />
</bag>
<one-to-one name="Profile" class="UserProfile" cascade="save-update" />
<one-to-one name="MatchCriteria" class="UserMatchCriteria" />
<one-to-one name="MatchLifestyle" class="UserMatchLifestyle" />
<property name="LastUpdated" />
</class>
As you can see I am trialing it just with the Profile object for now to try and get it working. How can I have it so that the main User object saves first, then passes the UserId to the other classes as they all use that as their primary key?
Again I could not do the cascade save, then set the UserId manually on each sub class and save them separately, but I am trying to do it in a single call.
I would say that you are almost there. your
userclass mapping seems correct, so the suspected for me isUserProfile.NHibernate supports exactly this style of relations and it is the
one-to-onemapping (as you’ve tried). While we cannot see the UserProfile mapping, let’s extend it following the documentation:UserProfilehbmThe UserProfile need these properties:
Before insert we have to connect both ends (this is very important step):
and if the cascade mapping in the
user.hbm.xmlwill look like this:we can save just a
userand all other entities will be (in correct orther) persisted by NHiberante. No need to handle ID anyhow.