NHibernate Composite Index, not a key - nhibernate

Still a n00b in NHibernate :(
I want to add a composite index to the hbm.xml of one of my POCOs, for performance purposes. It does not relate directly to a class, but rather two common values I will be querying against.
I think I need to do a <map></map> entry in the XML, but the XSD is asking for a class name on the composite-key element, and there is no direct relationship, per se... plus it's asking for more information than I think I would need to provide. How do I do this?
<map name="PropertyKeys">
<key>
<column name="StockID" />
<column name="PropertyName" />
</key>
<composite-index class="Something?">
<key-property name="What goes here?" />
</composite-index>
<what else goes here?>
</map>

Have you read this http://ayende.com/blog/4045/nhibernate-mapping-map It explains when you would use a map and further on it explains the composite-index
However without more background info it is not 100% certain that you need a map!

Related

Hard Coded Values In Nhibernate Mapping Files

I am pretty new to NHibernate and I'm trying to create a mapping file to extend a data model project. The particular table I am mapping is called AttributeDef in the following image, the column ControlType actually relates to a lookup in the table called Code (yes, I know - there should be an FK constraint but this sort of thing is quite common in this project so please ignore the obvious howlers and focus on the question). In most cases tables which reference Code also have a column which contains the ID from the table CodeSet as the key in Code is, almost inevitably, a composite key, but not in this case presumably because the original author figured "Hey they're all from the same codeset so what's the point?".
Now if there was a column in AttributeDef which contained the CodeSet value then the mapping wouldn't be much of a problem. The mapping for the Code entity looks like this:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Activus.DataModel" namespace="Activus.DataModel">
<class name="Code" table="Code" mutable="false">
<composite-id name="CompositeCodeId" class="CompositeCodeId">
<key-property name="CodeId" column="CodeId"/>
<key-property name="CodeSet" column="CodeSet"/>
</composite-id>
<property name="Description" column="Description" type="string" length="100" not-null="true"/>
<property name="ExternalRef" column ="ExternalRef" type ="string" length ="256" not-null ="true"/>
<property name="InternalRef" column ="InternalRef" type ="string" not-null ="false"/>
<many-to-one name="CodeSet" class="CodeSet" column="CodeSet" not-null="true" insert="false" update="false"/>
</class>
</hibernate-mapping>
Therefore if there was a column in AttributeDef for the CodeSet value (notionally called FormControlCodeSet in this example) then in my AttributeDef mapping file I would include
<many-to-one name="ControlType" class="Code" not-null="false">
<column name="ControlType" />
<column name="FormControlCodeSet" />
</many-to-one>
And all should be well. The problem is that to add that column to AttributeDef would be very invasive as I would then have to make a LOT of other changes to accommodate this and that would increase the risk factor of the change I'm making to a point which might well be unacceptable (from the client's point of view given their time frame).
So, much as it's a horrible, horrible thing to contemplate, Is it possible to substitute the line
<column name="FormControlCodeSet" />
With a (whisper it) hard coded value? That value hasn't changed in a decade and isn't likely to anytime soon but it would get us past this change and would highlight the need to scope out and implement the inclusion of the extra column. I recognise how dreadful this is but unfortunately a lot of this database isn't really that well suited to ORM despite it's being shoe-horned in anyway.
You do not have to whisper requirements, when working with NHiberante. Because cooperation with legacy DB (i.e. fixed DB schema) is pretty standard, NHibernate does support many different settings.
One of these is a pair of (substitutional) settings: "column" vs "formula". The first takes the column as is, the second could do whatever we need. Take column, columns, pass a constant. So:
<many-to-one name="ControlType" class="Code" not-null="false">
<column name="ControlType" />
<!-- let's replace this -->
<!--<column name="FormControlCodeSet" />-->
<!-- 1) with a constant number 123-->
<formula>123</formula>
<!-- 2) with a constant string 'constantString' -->
<formula>'constantString'</formula>
</many-to-one>
Not sure if the FormControlCodeSet constant should be int or string, but as shown above, either option is possible.

"Invalid Index n for this SqlParameterCollection with Count=n" OR "foreign key cannot be null"

I have been successfully using NHibernate for quite some time now and
have been able to solve a lot of pitfalls with an application that I
developed with it and that is running in production. The recent hurdle
really has me scratching my head, though.
Recently I had to expand the class library with some new classes that
are nested as children to some already existing classes. I just copied
the same model for aggregate mapping that I already was successfully
using, but this time it does not work.
Now when I use the following in the parent mapping file:
<bag name="SeaInfoItems" table="EDIImport_SeaInfo" lazy="false" cascade="save-update">
<key column="EDI_FK_OWNERID"/>
<one-to-many class="FargoGate.AppLib.EdiImportSeaInfo, FargoGate.AppLib"/>
</bag>
I can choose to, in the child class, either use:
<property name="EDI_FK_OWNERID" column="EDI_FK_OWNERID" />
...which gives me the infamous "Invalid Index n for this
SqlParameterCollection with Count=n" error.
OR I try with this solution I found after some Googling:
<property name="EDI_FK_OWNERID" column="EDI_FK_OWNERID" insert="false" update="false" />
...which gives me a "Cannot insert the value NULL into column
'EDI_FK_OWNERID'... column does not allow nulls." error.
So basically I have to choose between pest and cholera.
What I don't get is that it works flawlessly for the already existing
aggregate classes, and I really cannot spot the difference. The only
thing is that this foreign key (EDI_FK_OWNERID) could refer to two
different parent tables. Bad database design, I know, but I didn't
design it, and it is my task to develop up to it for better or worse. I cannot change the database design.
The other difference is that I totally removed the foreign key reference from the already existing child classes (the mappings as well as the class members). I tried to emulate that of course, but of no avail.
Also I discovered that one of the new classes (which is quite small) also works fine. But I cannot see what the difference is here either. I am stumped!
Anyone has a clue?
Aaargh! I was put so much on a wrong leg with this infamous “Invalid Index n for this SqlParameterCollection with Count=n” error that I overlooked the obvious: A duplicate mapping of a field for ONE of the classes.
In that particular mapping I left this error, where the primary key is also defined as a property:
<id name="ID" column="ID">
<generator class="guid" />
</id>
<property name="ID" column="ID" />
Now that was a waste of time trying to debug that!

What would cause NHibernate to return an invalid identity selection when using JET?

Our application (sadly) uses an MDB back-end database (I.e. JET engine).
One of the items being persisted to the database is an "event" object. The object is persisted to a table with an ID (EventLogID) that is an Autonumber field. The NHibernate mapping is as follows:
<class name="EventLogEntry" table="tblEventLog" proxy="IEventLogEntry">
<id name="Id">
<column name="EventLogID" not-null="true" />
<generator class="native" />
</id>
<property name="Source" column="ErrorLogSource" />
<property name="Text" column="EventLogText" />
<property name="Time" column="EventLogTime" />
<property name="User" column="UserID" />
<property name="Device" column="EventDeviceID" />
</class>
According to the log file, on some occasions when NHibernate attempts to obtain the identity, it receives the value "0". Later, when Flush is called, NHibernate suffers from an assertion failure.
Can anyone suggest why this might be happening? Better yet, can anyone suggest how to fix it?
Regards,
Richard
It could be that the default 'connection-release-mode' configuration setting is the cause of the problems.
A while ago, I ran into a similar issue, and I found that changing the connection.release-mode to 'on_close' (instead of the default after_transaction) solved the issue.
More information can be found on my blog
edit: as I'm thinking of it, perhaps it can be solved without changing the release-mode as well; what happens if you use a transaction to save your event ?
The default release-mode is after transaction, so I'm thinking; perhaps when you use an explicit transaction, the connection will only be closed after the transaction. The question offcourse is, will NHibernate try to retrieve the primary key that has been given to the object inside this transaction, or will it use another transaction ...
If it does not work, then changing the release-mode will solve your problem as well, but it is maybe not the best option.
I think the best option/solution, is to use an explicit transaction first, and see if this solves the problem...

Hibernate mappings: Splitting up the file

Alright, I've got a quick question. I'm currently working with a legacy database, so I can't change around much. The database revolves around a single type, the entity. All other relevant data (except for customizable lists etc.) 'inherit' from this.
I'm mapping this with a joined subclass approach, which is working fine. The problem however, is that my mapping file is reaching hideous proportions. I would like to split up the file in multiple separate files, but I'm not sure if this is possible and how to approach this problem. I've read through the Hibernate docs on the official site, but couldn't find anything.
To clarify, mappings look like this:
<class name="..." table="...">
<id ...>
<generator class="org.hibernate.id.TableHiLoGenerator">
<param name="table">...</param>
<param name="column">...</param>
</generator>
</id>
<property name="somethingCommon" />
<joined-subclass name="class_1">
...
...
</joined-subclass>
<joined-subclass name="class_2">
...
...
</joined-subclass>
...
<joined-subclass name="class_n">
...
...
</joined-subclass>
</class>
What I would like to be able to do is put the joined-subclass bits in separate files, just like I would do in code (separate classes -> separate files). Is this possible using just mappings, or perhaps by manipulating the mappings when I load them?
(Note: tagged hibernate/nhibernate, as I don't think this is specific to either flavor)
I believe you can use "extends" eg:
<hibernate-mapping>
<joined-subclass name="DomesticCat" extends="Cat">
...
</joined-subclass>
to separate out the joined subclasses into separate files.

nHibernate mapping generic IDictionary

I've asked this elsewhere and not got any sensible reply
I'm trying to map an IDictionary. I have this mapping:
<class name="MyProject.Item, MyProject" table="Item">
<...>
<map name="Properties" access="property" table="ItemProperties" lazy="false">
<key column="ItemID" />
<index column="Idx" type="int" />
<element column="Value" type="System.Boolean, mscorlib"/>
</map>
I can persist data, but when the data is retrieved I get an nHibernate exception:
{"The value "0" is not of type "Project.PropertyType" and cannot be used in this generic collection. Parameter name: key"}
So it can't map to the enum, but why ? if I have a regular property that uses an enum, it works fine.
Is what I'm trying to do even possible ? I can't find much info on doing this.
Your mapping shows the key as an integer, not as an enum. To map the enum properly, use type="MyProject.Project.PropertyType, MyProject".
However, normally for an enum the best approach is to leave the type information out of the mapping file altogether and let NHib pick it up through reflection. My reading of the NHib source implies that if you are mapping into a generic IDictionary<K,V> then NHib should pick up the exact type of your key via reflection. IOW you still should be able to leave out the type attribute.