Controlling uniqueness in a NHibernate composite-element - nhibernate-mapping

I have the following mapping:
...
<set name="Tests" table="InstrumentTests">
<key column="InstrumentId" />
<composite-element class="InstrumentTest">
<property name="TestInstrumentId" not-null="true" />
<property name="OtherTestId" />
</composite-element>
</set>
I'd like to make InstrumentId and TestInstrumentId unique so the table InstrumentTest cannot contain:
InstrumentId TestInstrumentId OtherTestId
1 TEST1 ABC
1 TEST1 BCD <--- NO
2 TEST1 ABC <--- OK, different InstrumentId
Maybe what I want is imposible using composite-element, but then how should I map this.

Ok, I found the solution. I need to implement Equals and GetHashCode for the InstrumentTest class.
It's clearly stated on the nHiberntate documentation:
Note: if you define an ISet of composite elements, it is very important to implement Equals() and GetHashCode() correctly.

Related

Fluent NHibernate Complex Composite Key Mapping

I'm afraid to even ask this question really, as I find the whole thing pretty disgusting myself. But, what are you going to do with a legacy database.
I have the following three tables
Generator Alarm AlarmDescription
--------- ----- ----------------
Id Id
Id <- GensetId DescriptionText
EventTypeId -> AlarmCode
PanelId ----------------> PanelId
If it's not clear from the above rendering, I have an Alarm, which has both a Genset and an AlarmDescription. The Genset is directly mappable via the GensetId property. The AlarmDescription should also be easily mappable off the Id property right? But it wasn't designed that way, and instead is mapped off a composite of (AlarmCode, PanelId) (note, they don't even share the same field name, found this out after struggling to find any relation until inspecting the data).
So, how would you map this using Fluent NHibernate? I've tried a couple variations, but have failed. Something like the following would be ... ideal, but I don't think anything like this is necessarily directly available.
References(x => x.AlarmDescription)
.Column("AlarmCode", m => m.EventTypeId)
.Column("PanelId", m => m.Genset.PanelId)
Have you tried formulas? (Sorry, I am not using fluent.)
<many-to-one name="AlarmDescription">
<column name="EventTypeId" />
<formula>(select g.PanelId from Generator g where g.Id = GensetId)</formula>
</many-to-one>
This requires declaring AlarmDescription primary key as being the composite id (AlarmCode, PanelId).
If you need to preserve AlarmDescription id, then add in it a natural-id as a component:
<class name="AlarmDescription">
<id name="Id">
<generator .../>
</id>
<natural-id>
<component name="AlarmDescriptionNaturalId">
<property name="AlarmCode" />
<property name="PanelId" />
</component>
</natural-id>
...
And reference it as the key for your relation in Alarm thanks to property-ref:
<many-to-one name="AlarmDescription" property-ref="AlarmDescriptionNaturalId">
<column name="EventTypeId" />
<formula>(select g.PanelId from Generator g where g.Id = GensetId)</formula>
</many-to-one>

How to persist a subset of an object instead of the whole object?

I'm struggling with a NHibernate related problem where I could use some input.
Introduction:
I have a legacy database where the relational concepts have not really been applied.
In the database I have an OrderLine table which contains data for an order lines.
On top of that the table also contains all columns with Order specific information. This could for example be order number of a customer.
E.x. If i have 10 order lines - then I have 10 rows in my OrderLines table and each row has all the Order specific data e.g. order number or customer information.
I did not want to have the above structure in my code so a view was created for Orders so that I could map my Order in NHibernate which then has a set/bag of OrderLines which makes much more sense.
Mapping: (simplified)
<class name="Order" table="[view_Orders]">
<bag name="OrderLines">
</class>
<class name="OrderLine" table="OrderLines" />
The problem:
The complexity of the view makes it impossible to save to the view. When trying NHibernates throws this exception:
NHibernate.Exceptions.GenericADOException: could not insert: XXX ---> System.Data.SqlClient.SqlException: View or function 'view_Orders' is not updatable because the modification affects multiple base tables.
My NHibernate mapping is constructed as an Order object which has a "set or bag" of OrderLine objects. Ideally I would like NHibernate only to persist the set of OrderLine objects instead of the whole object.
Is there a way of achieving this? I have tried locking the object using different lock modes but it did not help me.
You can use mutable="false" to avoid the update and deletes as this article says:
Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor performance optimizations.
To avoid the insert you can use the following statement (Uses the proyection instead an insert command, dont forget use check="none"):
<sql-insert check="none">SELECT 1</sql-insert>
Here is a tested example:
<class name="Order" table="[view_Orders]" mutable="false">
<id name="OrderId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="GrandTotal"/> -->
<set name="OrderLines" lazy="true" inverse="true" cascade="all-delete-orphan">
<key column="OrderId"/>
<one-to-many class="OrderLine"/>
</set>
<sql-insert check="none">SELECT 1</sql-insert>
</class>
<class name="OrderLine" table="OrderLine">
<id name="OrderLineId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="OrderId"/>
<property name="GrandTotal"/>/> -->
</class>
In case I do understand your issue, the solution is surprisingly simple. We just would mark root object with dynamic-update="true"
<class name="Order" table="[view_Orders]" dynamic-update="true">
...
</class>
And then apply update="false" to every property or reference which we have in that Order class mapped to view:
...
<property name="Code" update="false"/>
...
<many-to-one name="Country" update="false />
But our collection will need the standard, even cascade mapping:
<class name="Order" table="[view_Orders]" dynamic-update="true">
<bag name="OrderLines"
lazy="true"
inverse="true"
batch-size="25"
cascade="all-delete-orphan" >
...
</bag>
... // other stuff is update="false"
</class>
And now code like this would do management of OrderLines, while not executing any updates on the root object Order
var session = ... // get ISession
// load root
var root = session.Get<Order>(123);
// if needed change existing line (pretend there is one)
root.OrderLines[0].Amount = 100;
// add new
var newOrder = ... // new order
root.OrderLines.Add(newOrder);
session.Save(root);
session.Flush();
And that is it. Cascade on the root object is doing what we need, while the update="false" is not updating it...
NOTE: Just interesting note - there is also class and collection
setting mutable="false", but it would not work here... as the
solution mentioned above (it is sad, because that would be more
elegant, but not working as expected...). See:
19.2.2. Strategy: read only
If your application needs to read but never modify instances of a persistent class, a read-only cache may be used. This is the simplest and best performing strategy. Its even perfectly safe for use in a cluster.
<class name="Eg.Immutable" mutable="false">

NHibernate: Why would you use <composite-element> over <one-to-many> to map a collection

When using NHibernate, under what circumstances would you choose to map a collection using a composite-element to give a collection of value objects, rather than creating a full-blown entity and mapping it using one-to-many?
You might have a value-type class 'PostalAddress' to represent an address. If you had a person entity and each person could have many addresses you could map this relationship like this (Option 1):
<bag name="Addresses" table="PersonAddress">
<key column="PersonID"/>
<composite-element class="PostalAddress">
<property name="StreetAddress"/>
<property name="Town"/>
<property name="City"/>
<property name="Postcode"/>
</composite-element>
</bag>
Or you could create an entity 'PersonAddress' which has a 'PostalAddress' typed property on it and map the addresses with a one-to-many association (Option 2):
<bag name="Addresses">
<key column="PersonID"/>
<one-to-many class="PersonAddress"/>
</bag>
<class name="PersonAddress">
<id name="Id">
<generator class="native"/>
</id>
<component name="Address" class="PostalAddress">
<property name="StreetAddress"/>
<property name="Town"/>
<property name="City"/>
<property name="Postcode"/>
</component>
</class>
Are there any reasons not to do option 1? Does the fact that the PersonAddress table has an ID column suggest that it should be an entity itself, hence use option 2?
<composite-element> is for when you have a collection of values whereas <one-to-many> is a collection of entities. The defining characteristic of an entity is a unique identifier. So if the items in your collection have a PK, use <one-to-many>. Otherwise use <composite-element>.
Another way to think about it is how you determine equality. Do you determine equality by comparing an ID or by verifying that all properties are identical? e.g. In your application, do two objects represent the same address if (address1.Id == address2.Id) or if (address1.Street == address2.Street && address1.City == address2.City && etc.)? There is no universal right answer as it depends on application context. In many cases, money is a value object. Whether you have this $20 or that $20, it doesn't matter. Only the amount is relevant. If you were writing a tracking application for a mint, they probably need to know which $20 bill you're dealing with and you would track the serial number on the $20 bill. In this case, money is an entity. It all depends on application and context...

NHibernate: mapping user type object to a separate table

Let's start with this mapping:
<component name="Location">
...
<property name="Settings" type="JsonUserType,...">
<column name="LocationSettingsType" />
<column name="LocationSettingsData" />
</property>
</component>
This maps to
TABLE Primary (
...
LocationSettingsType,
LocationSettingsData
...
)
and
class Location {
...
object Settings { get; set; }
}
Now, I want to extract settings into a separate table (because they are seldom here).
So I get
TABLE Primary (
...
LocationSettingsId,
...
)
TABLE Settings (
Id,
Type,
Data
)
Can I keep my C# classes the same?
Update: This is not a many-to-one relationship. As before, each location has zero or one settings, and each settings belong to at most one location.
I believe the closest thing that exists to this is the <map> mapping element; details are explained in this article.
If you want a one to many relationship on the Primary and Settings tables, you'll have to set a foreign key constraint first. Then you'll use the bag property in XML to map your tables. You will have an entity for each table.
See also this question on NHibernate/FluentNHibernate Property Bag.
I also recommend you purchase the NHibernate 2 for Beginners book. It helped me alot.
This is an old question but i had the same issue and looking to a solution I came here.
the component element can map several columns to several object models.
the join element can map several tables to an object model.
The main problem is that while the component cannot map columns from a different table where the model belong, the join cannot map the different table columns to a different object model.
The solution I found is to use both to achieve the map column of a different table to several object:
<class name="Primary" table="Primary">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Name" />
...
<join table="Settings">
<key column="PrimaryId"/>
<component name="Location">
...
<property name="Settings" type="JsonUserType,...">
<column name="LocationSettingsType" />
<column name="LocationSettingsData" />
</property>
</component>
</join>
</class>
Reference:
NHibernate Join mapping element
NHibernate Component mapping element

Hibernate Next/Previous Sibling Mapping

I'm using nHibernate to map an object very similar to .NET's System.Web.SiteMapNode. In order to keep my object similar to this .NET object I would like to have it contain a ParentNode, PreviousSibling, NextSibling, and ChildNodes complex properties.
The table looks somewhat like this and is open to be changed:
ID (int)
Title (string)
Description (string)
Key (string)
ParentNodeId (int)
OrdinalPosition (int)
ReadOnly (bool)
Url (string)
I may have some other properties that are not needed to mimic the .NET SiteMapNode object (like an isExternal bool), but I think those are inconsequential to this question.
My current mapping looks like this:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="AthletesCafe.Core.Domain.System.SiteMap" assembly="AthletesCafe.Core">
<class name="SiteMapNode" table="SiteMapNode" lazy="true" >
<id name="ID" type="Int32" unsaved-value="0">
<column name="ID" not-null="true" unique="true" index="PK_SiteMapNode"/>
<generator class="identity" />
</id>
<property name="Title" column="Title" type="String" length="255" not-null="true" />
<property name="Description" column="Description" type="String" not-null="false" />
<property name="Url" column="Description" type="String" not-null="true" />
<property name="SiteMapKey" column="SiteMapKey" type="String" not-null="true" length="255" />
<property name="OrdinalPosition" column="OrdinalPosition" type="Int32" not-null="true" />
<property name="ReadOnly" column="ReadOnly" not-null="true" type="System.Boolean" />
<property name="IsExternal" column="IsExternal" not-null="true" type="System.Boolean" />
<many-to-one name="ParentNode" column="ParentNodeId" class="AthletesCafe.Core.Domain.System.SiteMap.SiteMapNode, AthletesCafe.Core"
access="field.pascalcase-underscore" not-null="false" />
<many-to-one name="PreviousNode" column="ParentNodeId" class="EatMyTrainer.Core.Domain.SiteMap.SiteMapNode, EatMyTrainer.Core" not-null="false" /></hibernate-mapping>
The ParentNode mapping is easy as it should be just a simple many-to-one mapping. This is the code I have for it (untested, but I believe it to be correct):
<many-to-one name="ParentNode" column="ParentNodeId" class="AthletesCafe.Core.Domain.System.SiteMap.SiteMapNode, AthletesCafe.Core"
access="field.pascalcase-underscore" not-null="false" />
The mapping for the child nodes should just be a simple bag which will bring back all SiteMapNode objects that have the ParentNodeId equal to the current ID. I haven't written this bag yet, but I believe it to be not such a big deal.
The issue that I cannot seem to resolve is how to do the Next/Previous Sibling properties. This objects can be derived from the following formula for each node:
PreviousSibling: Has the same ParentNode (ParentNodeId) as the current object and its OrdinalPosition should be one less than the current object's OrdinalPosition.
NextSibling: Has the same ParentNode (ParentNodeId) as the current object and its OrdinalPosition should be one more than the current object's OrdinalPosition.
I think this is achievable through the formual attribute on a many-to-one mapping. Is this possible? I haven't found a good example of how this works.
I don't think what you're asking for is strictly possible (although I would be very interested to see the solution if it is). There would be a relatively simple workaround, but NHibernate does not support bidirectional one-to-many mappings with indexed collections on the many end.
The only thing that comes to mind is a bit ugly: have the parent object keep its own index map (keyed off the OrdinalPosition) to each child object. On the child do something like:
public SiteMapNode NextSibling()
{
return this.Parent.NextSibling(this);
}
I believe Stuart is correct in this situation. It is impossible to do for the many-to-one mapping. If NHibernate provided a way to do where clausing on this mapping then I may have a chance.
Another possible solution although inefficient is to create a bag that uses a field setter. The public property that would be Next/Previous setting would still return an object reference (as opposed to an enumerable). In the getter it would just reference the first position of the enumerable in the field. Lazy loading would be ideal because NHibernate wouldn't be able to load this object in one get with the initial load of the object. You would have a penalty for accessing this object every time.
I guess both solutions have a similar penalty.