NHibernate Many to One / One to One with differing keys - nhibernate

Hey all, I'm kicking the tires on NHibernate and have a conoundrum I have been scratching my head over for a bit now, working with a legacy database with some fairly complex relationships.
ClaimRoot has a primary key of a claimGUID.
ClaimRoot has a bag of Claimdetails associated by claimGUID (this works a treat).
The problem is that ClaimRoot also has an optional one to one relationship with ClaimFinancials (not all ClaimRoots have ClaimFinancials, but most do). But the PK for ClaimFinancials is a FormID field. This field exists in the ClaimRoot, but is not the PK.
I've posted a mapping below with extra columns removed to protect the innocent.
<class name="ClaimRoot" table="tbl_ClaimRoot" schema="DB1.dbo">
<id name="ClaimGUID">
<generator class="guid"/>
</id>
<property name="FormID" />
<property name="LastFormNoteText" />
<bag name="ClaimDetails" inverse="true">
<key column="ClaimGUID"/>
<one-to-many class="ClaimDetails"/>
</bag>
</class>
<class name="ClaimDetails" table="tbl_ClaimDetails" schema="DB2.dbo">
<id name="RowID">
<generator class="native"/>
</id>
<property name="ClaimGUID" />
<property name="SeqNo"/>
<property name="B1A_InsID" />
<many-to-one name="Root" column="ClaimGUID" foreign-key="ClaimGUID"/>
</class>
<class name="ClaimFinancials" table="tbl_ClaimFinancials" schema="DB1.dbo">
<id name="FormID">
<generator class="native"/>
</id>
<property name="CreatedDate"/>
<property name="SubmittedDate" />
</class>
Thanks in advance!
-Bob

Assuming the FormID is use only for linking ClaimRoot and ClaimFinancials, it sounds like you want a many-to-one relationship from ClaimRoot to ClaimFinancials. Replace the FormId property on ClaimRoot with a many-to-one.
<class name="ClaimRoot" table="tbl_ClaimRoot" schema="DB1.dbo">
...
<many-to-one name="ClaimFinancials" column="FormID" />
...
</class>
A many-to-one relationship can be be used even if there is only 'one' on the 'many' side. If you were generating a schema, you can specify unique="true" to generate the constraint in the database. With a legacy database, that won't matter.

Related

Nhibernate: one-to-one to one-to-one

I have the following UML structure:
I'm trying to map it similar to this:
<class name="Parent" table="ParentTable">
<id name="Id">
<generator class="guid.comb" />
</id>
<one-to-one name="Child" class="IChild" property-ref="Parent" cascade="all" />
</class>
<class name="IChild" table="ChildTable" abstract="true">
<id name="Id">
<generator class="foreign">
<param name="property">Parent</param>
</generator>
</id>
<discriminator column="TypeKey" type="String"/>
<one-to-one name="Parent" class="Parent" />
<one-to-one name="Child" class="IGrandchild" property-ref="Parent" cascade="all" />
</class>
<subclass name="ConcreteChild" extends="IChild" discriminator-value="ConcreteChild1">
<property name="SomeProperty"/>
</subclass>
<class name="IGrandchild" table="GrandchildTable" abstract="true">
<id name="Id">
<generator class="guid.comb" />
</id>
<discriminator column="TypeKey" type="String"/>
<many-to-one name="Parent" class="IChild" unique="true" column="ChildTableFk" />
</class>
<subclass name="ConcreteGrandchild" extends="IGrandchild" discriminator-value="ConcreteGrandchild1">
<property name="SomeOtherProperty"/>
</subclass>
Working against SQL this doesn't work (strangely, with SQLite this does work). NHibernate first inserts the Parent with the generated guid. It then inserts the child with the same guid. But when it comes to inserting the grandchild, it inserts it with ChildTableFk null (and never attempts to update the FK value).
Additional points:
I prefer not changing the IChild mapping to use many-to-one with FK if possible (I prefer a shared PK).
I can't change the IGrandChild mapping to use a foreign generator because the grandchild can be changed after the object graph is changed, which NHibernate does not support with a foreign generator (an IChild instance, on the other hand, will never change for the lifecycle of a given IParent).
Other than that, any suggestions are welcome, including alternate mapping styles (as long as they support polymorphic IChild and IGrandchild objects).
Oops, seems that I just forgot to set the Parent property on the Grandchild. Should have been the first thing I looked at.

NHibernate Mapping a sublass property to another object via foreign key

I am working on an existing data structure that is not perfect and I have an inheritance mapping issue to solve.
I am using a table per hierarchy and have subclasses with discriminators set up. However the subclassed properties are foreign keys back to other tables. How do I set up my subclass mapping so that when I query the fk property I get an object rather than null? Is this even possible?
My current Mapping
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MVC3" namespace="MVC3.Models">
<class name="Image" table="Images">
<id name="Id" column="ImageId">
<generator class="identity" />
</id>
<discriminator column="ImageType" />
<property name="Url" column="Url" not-null="true" />
<property name="Caption" column="Caption" />
<subclass name="AupairImage" discriminator-value="AupairImage">
<join table="Aupairs" inverse="true">
<key column="AupairId" />
<many-to-one name="Aupair" column="AupairId" class="Aupair" />
</join>
</subclass>
<subclass name="FamilyImage" discriminator-value="FamilyImage">
<join table="Families" inverse="true">
<key column="FamilyId" />
<many-to-one name="Family" column="FamilyId" class="Family" />
</join>
</subclass>
I would have like to add an entity diagram but I cannot post images yet :0(
But the foreign keys AupairId and FamilyId link off back to two other tables and are of the type int 32
I know it would be better to restructure the Aupair And Family entities to have a hierarchy to get rid of the one in images but this would be a last resort due to existing code.
Thanks in advance any help appreciated from you mapping experts....
Realised what I was doing wrong after taking a second look, should have just used a Many-To-One under the Subclass with a defined column
<subclass name="MVC3.Models.FamilyImage, MVC3" discriminator-value="FamilyImage">
<many-to-one cascade="all" class="MVC3.Models.Family, MVC3" name="Family">
<column name="FamilyId" />
</many-to-one>
</subclass>

Mapping the flip side of an NHibernate <any> association

Ayende has a great example of using the <any> mapping here, which I am reposting as part of my question since comments are closed on that blog post. Given his original mapping:
<class name="Order" table="Orders">
<id name="Id">
<generator class="native"/>
</id>
<any name="Payment" id-type="System.Int64" meta-type="System.String" cascade="all">
<meta-value value="CreditCard" class="CreditCardPayment"/>
<meta-value value="Wire" class="WirePayment"/>
<column name="PaymentType"/>
<column name="PaymentId"/>
</any>
</class>
<class name="CreditCardPayment" table="CreditCardPayments">
<id name="Id">
<generator class="native"/>
</id>
<property name="IsSuccessful"/>
<property name="Amount"/>
<property name="CardNumber"/>
</class>
<class name="WirePayment" table="WirePayments">
<id name="Id">
<generator class="native"/>
</id>
<property name="IsSuccessful"/>
<property name="Amount"/>
<property name="BankAccountNumber"/>
</class>
... how would I go about mapping a property named Order on the CreditCardPayment and WirePayment classes which would be the "flip side" of the association allowing traversal from these payments back up to the Order they are associated with?
The gotcha for me here is that CreditCardPayment and WirePayment can potentially have the same IDs since they are in different tables, so I need some way to tell NHibernate to take the PaymentType into consideration.
Bidirectional heterogeneous associations (i.e. <any>) are not supported by NHibernate.
I know this isn't what you wanted to hear, but that's it.

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

Can I "join" two tables into one class whilst also creating many-to-one relationships using NHibernate?

We have a legacy database schema which I've tried (unsuccessfully) to map with NHibernate. To give a simplified example, say I want a Person class whose first name comes from the "Person" table, but their last name comes from the "Person2" table. The "Person" table also has the Id of the person's Car and I want my Person class to have a Car property. I can map all that using the following;
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="NHibernateMappingTest.Person, NHibernateMappingTest" lazy="false">
<id name="Id" >
<generator class="native" />
</id>
<property name="FirstName" />
<many-to-one name="Car" access="property" class="NHibernateMappingTest.Car, NHibernateMappingTest" column="CarId" cascade="save-update"/>
<join table="Person2">
<key column="PersonId" />
<property name="LastName" />
</join>
</class>
</hibernate-mapping>
The lets me combine the Person and Person2 tables, and the lets me find their Car - everything works fine.
But... if the Person2 table happens to have the person's HouseId, I'd like to be able to add a second element to my mapping...
<many-to-one name="House" access="property" class="NHibernateMappingTest.House, NHibernateMappingTest" column="HouseId" cascade="save-update"/>
...so that my Person class can have a House property.
However this is where it all goes wrong, because the SQL which NHibernate generates assumes that the HouseId column is in the Person table (but it's not, it's in Person2), so I get the following error;
MySql.Data.MySqlClient.MySqlException: #42S22Unknown column 'HouseId' in 'field list'
Is NHibernate able to do what I'm attempting, is there a different way to achieve this (without changing the database schema), or have I just made a beginner's error in my map file?
Vincent - thanks for your response. No I wasn't nesting the tag element inside the element. But following your suggestion, I tried and it works perfectly! Thanks very much for responding.
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="NHibernateMappingTest.Person, NHibernateMappingTest" lazy="false">
<id name="Id" >
<generator class="native" />
</id>
<property name="FirstName" />
<many-to-one name="Car" access="property" class="NHibernateMappingTest.Car, NHibernateMappingTest" column="CarId" cascade="save-update"/>
<join table="Person2">
<key column="PersonId" />
<property name="LastName" />
<many-to-one name="House" access="property" class="NHibernateMappingTest.House, NHibernateMappingTest" column="HouseId" cascade="save-update"/>
</join>
</class>
</hibernate-mapping>