How do I map a composite key, if part of it is not mapped in my entity?
Example:
I have a table ITEMDELIVERY
containing the columns:
ITEMDELIVERY_ID
(PK)DELIVERY_DATE
(PK)
I have a table ITEMDELIVERYDETAIL
containing the columns:
ITEMDELIVERYDETAIL_ID
(PK)ITEMDELIVERY_ID
(FK)PARTITIONDATE
(PK, FK)
As you can see, there is a composite key in both tables and ITEMDELIVERYDETAIL
has a "composite" foreign key to ITEMDELIVERY
.
There exists no property PartitionDate in my domain model ItemDeliveryDetail
that could be mapped to the column PARTITIONDATE
(see here and here for the reasons).
But now, how do I map the composite key in ITEMDELIVERYDETAIL
?
I tried the following, but that doesn't work:
mapping.CompositeId().KeyProperty(x => x.Id, "ITEMDELIVERYDETAIL_ID")
.KeyProperty(x => x.ItemDelivery.DeliveryDate,
"PARTITIONDATE");
I get the following error:
NHibernate.PropertyNotFoundException: Could not find a getter for property 'DeliveryDate' in class 'REM.Domain.NHibernate.ItemDeliveryDetail'
UPDATE:
I think I found the solution:
- Remove the reference to
ItemDelivery
from the mapping ofItemDeliveryDetail
:mapping.References(x => x.ItemDelivery);.Columns("ITEMDELIVERY_ID", "PARTITIONDATE");
Change the declaration of the composite key to this:
mapping.CompositeId().KeyProperty(x => x.Id, "ITEMDELIVERYDETAIL_ID") .KeyReference(x => x.ItemDelivery, "ITEMDELIVERY_ID", "PARTITIONDATE");
This has the side effect that saving an ItemDeliveryDetail
can't cascade save an ItemDelivery
. It needs to be saved upfront.
However, I wonder about one thing:
Will this create a PK with three columns? If so, how to avoid it and only create a PK for the two columns needed?
it looks like you have a legacy db and will never generate it with SchemaExport, so it doesnt matter if NH thinks it has 3 PK columns or 1.
after looking at your question Composite key with sequence and if your Id is unique alone then it would be better to
even if in the db the PK spans both columns
Update: tricky thing in your example of Invoice. There is a hack to have the second column in the join (as a where which the query optimizer should add to the join)