NHibernate multiple primary keys mapping - nhibernate

I have a table called "Orderrow". Orderrow has a a compound primary key (CPK) with the following columns: OrderId, ProductId, RowNumber
OrderId and ProductId are also foreign keys refering to the tables Order and Product. The RowNumber is generated in the app.
I was wondering how this is mapped in NHibernate because I can only set 1 id element and 1 generator subelement.

Here is an example using the composite-id property in a NHibernate mapping file:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain.Model">
<class name="Program" table="program">
<composite-id>
<key-property name="Id" column="id"></key-property>
<key-property name="Prog" column="prog"></key-property>
<key-property name="Site" column="site"></key-property>
</composite-id>
<property name="ActiveDate" column="active_date"/>
<property name="Year" column="year"/>
</class>
</hibernate-mapping>

There is a 'composite-id' property you can use in your class mapping instead of the 'id' property. However, you should know that the nHibernate team strongly discourages the use of it. It sounds like you are dealing with a legacy database, in which you have no control over the schema. So, the 'composite-id' is specifically for your situation.
Check out the NH docs for more info: http://nhibernate.info/doc/nh/en/index.html

Personally I do not like to have compound primary keys in my database table schemas, plus they usually are 'hard' to handle by any ORM mapper I tried.
If I have to give a unique identity to a row in a table (especially if it represents a business object), I prefer to use a single value surrogate Id - a GUID or an Integer - if any of the fields in the table isn't suitable.
Using a composite Id is always troublesome when writing interrogation queries and joins, so my usual strategy is to use a surrogate Id (which has no meaning to the business object but to identify the object itself) and place a unique constraint on the fields of the previous CPK.

Related

Unique names in primary keys

I have db tables in each I have same primary column name ('ID')
I get error from nhibernate:
System.IndexOutOfRangeException : An SqlCeParameter with
ParameterIndex '5' is not contained by this SqlCeParameterCollection
When I change these columns names to unique names, all is ok.
But i wonder how to fix it without name changes. I simply want same name in each table.
<class name="AppSignature" table="app_signatures" lazy="true">
<id name="Id"><generator class="guid"></generator></id>
</class>
<class name="AppState" table="app_states" lazy="true">
<id name="Id"><generator class="guid"></generator></id>
<many-to-one name="app_signature"
class="AppSignature"
column="Id"
foreign-key="id_fom_app_signature"
not-null="true"
>
</many-to-one>
</class>
Many-to-one relation means that an AppState instance can be assigned at most to one AppSignature instance. To an AppSignature can be assigned any number of AppState instances. This relation is implemented as an foreign key from app_states table to app_signatures table. "Column" attribute in "many-to-one" element determines column name that stores a value for the foreign key. To the Id column are mapped two AppState members: Id and app_signature which is not possible in NH and leads to the described exception.
The fix is easy:
<many-to-one name="app_signature"
class="AppSignature"
column="app_signature_id"
foreign-key="id_fom_app_signature"
not-null="true"
>
</many-to-one>
Name of column that implements foreign key was changed to an unique name: "app_signature_id". Now app_signature member is mapped to AppState.app_signature_id column which points to the app_signatures.Id column
However described exception should disappear (if the new column is properly added to app_signatures table) it would not necessarily be what you you really want. The relation between AppState and AppSignature could be one-to-one. It means an AppState instnace can be assigned to a single AppSignature instnance and vice versa. Such relation could be implemented by a primary and foreign key on the same column. There is a very nice article about one-to-one relations.

NHibernate issues redundant queries with composite keys

For the sake of the example, let's say that I have to model the "person" entity of the database of my country's revenue service, and that in my very small country the first name and the last name of a person are enough to uniquely identify the person. Additionally, the revenue service's database does not use surrogate keys, and adding a surrogate key to it would zero out the GDP of the country for the next 10 years.
The Persons table has three fields:
FirstName
LastName
CurrentAddress
And, given the size of my country, the table has a unique constraint on the <FirstName, LastName> pair of columns.
Given this schema, my very simple Person class has the following members:
Key: an instance of a PersonKey class, which in turn has FirstName and LastName members, and of course implements Equals() and GetHashCode();
CurrentAddress: a simple string.
The NHibernate mapping looks as follows:
<class name="Person" table="Persons" lazy="false">
<composite-id name="Key" class="PersonKey">
<key-property name="FirstName" type="string" column="FirstName"/>
<key-property name="LastName" type="string" column="LastName"/>
</composite-id>
<property name="CurrentAddress" type="string" column="CurrentAddress" not-null="true" />
</class>
So far so good, this mapping works fine and I can happily load Person entities from the DB.
However, when I look under the hood, I can see that when loading the entire set of persons, NHibernate does the following:
Opens a recordset to load key properties only (i.e. exclusively the FirstName and LastName fields) from the Persons table;
For each <FirstName, LastName> pair loaded from Persons, it issues a SELECT - of course against Persons as well - to load the CurrentAddress for the person having that FirstName and LastName.
In other words, NHibernate is first loading the keys, and then it issues a series of SELECT's to load each Person separately providing the key in the WHERE clause.
Provided that I am not interested in writing to the database, is there a way to tell NHibernate that it could use a single recordset to retrieve both key and non-key properties from the table?
IQuery.Enumerable has the behavior you mentioned in your comment (loads the keys first, the elements on MoveNext)
In any case, NH is not designed for the mass-processing scenario you are trying to create.
You'll have much better performance by using a raw DataReader.

Using part of a composite primary key in a composite foreign key in NHibernate

We have a fairly big DB (~200 tables) which almost entirely uses composite primary keys and composite foreign keys, using a single "base table" from which every other table inherits part of its primary key:
Parent has single column primary key ParentId
Child has composite primary key (ParentId, ChildId) and foreign key ParentId
Nephew has composite primary key (ParentId, NephewId), foreign key ParentId and foreign key (ParentId, ChildId)
and so on. Up until now we managed this whole shebang with an ORM framework of our own, but we're considering using NHibernate, which I've been assigned to learn (i've downloaded v2.1.2).
The mappings:
Child
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Assembly" namespace="Namespace">
<class name="Child" table="Child">
<composite-id name="IdChild" class="ChildId">
<key-many-to-one name="Parent" column="ParentId" class="ParentId"></key-many-to-one>
<key-property name="Id" column="ChildId" type="Int32"></key-property>
</composite-id>
<!--simple properties-->
<set name="Nephews" table="Nephew">
<key>
<column name="ParentId"></column>
<column name="ChildId"></column>
</key>
<one-to-many class="Nephew"/>
</set>
</class>
</hibernate-mapping>
Nephew
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Assembly" namespace="Namespace">
<class name="Nephew" table="Nephew">
<composite-id name="IdNephew" class="NephewId">
<key-many-to-one name="Parent" column="ParentId" class="Parent"></key-many-to-one>
<key-property name="Id" column="NephewId" type="Int32"></key-property>
</composite-id>
<many-to-one name="Child" class="Child">
<column name="ParentId"></column>
<column name="ChildId"></column>
</many-to-one>
<!--simple properties-->
</class>
I can post the classes too if you want, I'll omit them now for brevity (as I'll omit the mapping for Parent, since it doesn't have problems). Every property is virtual, every mapping file is an embedded resource, every composite Id has its own class which overrides Equals and GetHashCode.
The problem is I can't save an instance of Nephew, initialized through a simple new Nephew() and passed on to _session.Save(), because I get a System.IndexOutOfRangeException: Invalid index n for this SqlParameterCollection with Count=n..
The only column which is duplicated in the mapping is the ParentId. Removing the many-to-one mapping in the Nephew, the set mapping in the Child and all related properties everything works fine.
I found several posts reporting this exception, and the most appropriate in my case seems to be this one, which gives me the gut feeling that my current schema is infeasible with NHibernate. Please tell me I'm wrong :-)
NOTES:
I'm not using Fluent right now, even though it may be an option, but I preferred learning the basics first;
Yes, we realize composite primary keys are a big pain in the ass. This DB has passed through several hands through the years, probably not so skilled ones, but before refactoring it we will count to 10 000
Unfortunately, you won't be able to map that relationship in its current form, as you have inferred.
However, there's a workaround. Instead of mapping Nephew.Child as a many-to-one, map ChildId as a regular property, and use a query when you need to retrieve the Child.
There's one more chance for a hack. If and only if Nephew.Child is not null and not mutable, you could map the key referencing the Child instead of the parent:
<class name="Nephew" table="Nephew">
<composite-id name="IdNephew" class="NephewId">
<key-many-to-one name="Child">
<column="ParentId">
<column="ChildId">
</key-many-to-one>
<key-property name="Id" column="NephewId"/>
</composite-id>
</class>
I found a better solution:
<many-to-one name="Child" class="Child">
<formula>ParentId</formula>
<column name="ChildId"></column>
</many-to-one>
I had already tried that and it gave me an error, but then I noticed this patch, so I downloaded the 3.0.0 alpha2 and it all worked correctly! Thanks to this solution I can map the Nephew.Child property as it was meant to be.
I still need the Child.Add(Nephew) method, though (but I realized that is recommended even in the documentation)

When to use inverse=false on NHibernate / Hibernate OneToMany relationships?

I have been trying to get to grips with Hibernate's inverse attribute, and it seems to be just one of those things that is conceptually difficult.
The gist that I get is that when you have a parent entity (e.g. Parent) that has a collection of Child objects using a one-to-many mapping, setting inverse=true on the mapping tells Hibernate that 'the other side (the Child) has responsibility to update itself to maintain the foreign key reference in its table'.
Doing this appears to have 2 benefits when it comes to adding Children to the collection in your code, and then saving the Parent (with cascade-all set): you save an unneccessary hit on the database (because without inverse set, Hibernate thinks it has two places to update the FK relationship), and according to the official docs:
If the column of a
association is declared
NOT NULL, NHibernate may cause
constraint violations when it creates
or updates the association. To prevent
this problem, you must use a
bidirectional association with the
many valued end (the set or bag)
marked as inverse="true".
This all seems to make sense so far. What I don't get is this: when would you NOT want to use inverse=true on a one-to-many relationship?
As Matthieu says, the only case where you wouldn't want to set inverse = true is where it does not make sense for the child to be responsible for updating itself, such as in the case where the child has no knowledge of its parent.
Lets try a real world, and not at all contrived example:
<class name="SpyMaster" table="SpyMaster" lazy="true">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Name"/>
<set name="Spies" table="Spy" cascade="save-update">
<key column="SpyMasterId"/>
<one-to-many class="Spy"/>
</set>
</class>
<class name="Spy" table="Spy" lazy="true">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Name"/>
</class>
Spymasters can have spies, but spies never know who their spymaster is, because we have not included the many-to-one relationship in the spy class. Also (conveniently) a spy may turn rogue and so does not need to be associated with a spymaster. We can create entities as follows:
var sm = new SpyMaster
{
Name = "Head of Operation Treadstone"
};
sm.Spies.Add(new Spy
{
Name = "Bourne",
//SpyMaster = sm // Can't do this
});
session.Save(sm);
In such a case you would set the FK column to be nullable because the act of saving sm would insert into the SpyMaster table and the Spy table, and only after that would it then update the Spy table to set the FK. In this case, if we were to set inverse = true, the FK would never get updated.
Despite of the high-voted accepted answer, I have another answer to that.
Consider a class diagram with these relations:
Parent => list of Items
Item => Parent
Nobody ever said, that the Item => Parent relation is redundant to the Parent => Items relation. An Item could reference any Parent.
But in your application, you know that the relations are redundant. You know that the relations don't need to be stored separately in the database. So you decide to store it in a single foreign key, pointing from the Item to the Parent. This minimal information is enough to build up the list and the reference back.
All you need to do to map this with NH is:
use the same foreign key for both relations
tell NH that one (the list) is redundant to the other and could be ignored when storing the object. (That is what NH actually does with inverse="true")
These are the thoughts which are relevant for inverse. Nothing else. It is not a choice, there is only one way of correct mapping.
The Spy Problem:
It is a completely different discussion if you want to support a reference from the Item to the Parent. This is up to your business model, NH doesn't take any decisions in this. If one of the relations is missing, there is of course no redundancy and no use of inverse.
Misuse: If you use inverse="true" on a list which doesn't have any redundancy in memory, it just doesn't get stored. If you don't specify the inverse="true" if it should be there, NH may store the redundant information twice.
If you want to have an unidirectional association i.e. that the children can't navigate to the Parent. If so, you FK column should be NULLABLE because the children will be saved before the parent.

Fetch child without primary key NHibernate

I am trying to get a collection of objects into a parent object through mapping.
I have a parent object "ScoreCard" whose primary key is a guid (Id) and a child "Score" object whose primary key is a guid (Id). I want to select the child objects for the parent based on two fields that both objects have but I can't get it to work, here's the mapping
<bag name="ScoreCard">
<key>
<column name="HoleId"/>
<column name="PlayerId"/>
</key>
<one-to-many class="Score" not-found="ignore"/>
</bag>
I didn't design the database but the ScoreCard object comes from a view that returns both column I need plus the evil guid. Whatever I've tried, NHibernate keeps throwing an exception about the foreign key not being the same as the primary key.
This seems to me to be the most simple requirement, get a collection of things given some criteria, why am I so stuck?
Thanks for your help, sorry for the bad example code (subliminal golf watching at relatives house).
Well, I found it eventually. The parent object is drawn from a view giving three columns and no key. I can map a composite key to the HoleId and PlayerId instead of the evil guid that I found when I looked at the code. This is great as I can easily map the Score objects I need and then lazy load them using NHibernateUtil.Initialize.
My mapping xml needs to look like this
<class name="ParentObject">
<composite-id>
<key-property name="HoleId" column="HoleId" />
<key-property name="PlayerId" column="PlayerId" />
</composite-id>
<property name="EvilGuid" column="Id" />
<bag name="ScoreCard">
<key>
<column name="HoleId"/>
<column name="PlayerId"/>
</key>
<one-to-many class="Score" not-found="ignore"/>
</bag>
</class>
I got my inspiration from this post, please also pay attention to Stefan's answer as I feel I had a lucky break here, and the design could be made better with more thought about DDD.
Thanks for your help.
The problem is this: NHibernate works best (but not only) for DDD, this means for creating domain classes first and make the database best fitting the domain model.
You have a composite-id relation to non-primary-key fields. So start praying that NHibernate can cope with that. Both composite-ids and relations by non-primary-keys are supported - for legacy databases - and generally discouraged for DDD.
I think the combination of both does not work. See this issue on NHibernates issue tracker:
https://nhibernate.jira.com/browse/NH-1722. You can vote for the feature there.