Querying by property of mapped subclass in NHibernate - nhibernate

I'm very new to NHibernate so this may be fairly trivial, but searching is leaving me confused.
I have an AddOnAmount table as follows:
AddOnID | AddOnTypeID | Period | Amount
where AddOnTypeID is a FK. The rows have a unique constraint on AddOnTypeID and Period.
The mapping looks like this:
<id name="Id" column="AddOnId" type="long">
<generator class="native" />
</id>
<many-to-one name="AddOnType" column="AddOnTypeID" class="AddOnTypeStatic" not-null="true" />
<property name="Period" />
etc.
The AddOnTypeStatic class/table just has an Id, which is the numerical value stored on the table, and a descriptive Name.
I'm trying to write a query that will search by AddOnTypeId and Period, so I can validate the existence (or not) of a row before attempting to add a duplicate from my front end, but I'm not sure how to do that as the AddOnAmountStatic class has a subclass whereas the table has just an Id.
So far I've written:
public AddOnAmountStatic FindByAddOnTypeAndPeriod(long addOnType, string period)
{
return FindOne(CreateCriteria()
.Add(Restrictions.Eq("AddOnTypeId", addOnType))
.Add(Restrictions.Eq("Period", period))
.SetCacheable(true));
}
which does not work, as AddOnTypeId isn't a property of AddOnAmountStatic. Not sure how to access the property of the subclass in this context.
My mapping works, as I've been using it so far with no problems.

Solved my problem - it was simple but thought I'd add the solution here in case it helps anyone else.
I'd been thinking of constructing the query from the table's perspective (i.e., with the AddOnTypeID), whereas what I should have done is look at it from the entity's perspective. In other words, I just needed to pass in an AddOnTypeStatic object.
What I did was take my AddOnTypeID parameter, check it exists through NHibernate (returning either an AddOnTypeStatic object or null) then passed that through to the original query. Final query is simply
return FindOne(CreateCriteria()
.Add(Restrictions.Eq("AddOnType", addOnType))
.(Restrictions.Eq("Period", period))
.SetCacheable(true));
Hope this helps another newbie!

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.

Mapping inherited class with nhibernate hbm

I Have 2 classes of the same table.
one class, "Entity", contains properties x,y,z from table ENTITY
and the derived class, "ExtendedEntity" contains some more properties (collections - relations to other tables).
I want to map both of them but i couldn't find a way to map subclasses without using discriminator (I dont need one, sometimes i want to select the Entity object and sometimes the ExtendedEntity).
does anyone has any idea?
(I tried to map the ExtendedEntity by copying the Entity mapping and adding the new properties, but now when i want to get the Entity object it brings me ExtendedEntity).
Thanks!
Taking into account the first sentence of your question:
I Have 2 classes of the same table.
It means that there is only one table ("ENTITY"). If this is true, there do not have to be, and even should not be any inheritance, if no discriminator exists. If both entities will be related to all rows, then (instead of inheritance) we need laziness. And only one Entity profiting from the native NHibernate behavior: having lazy properties. And even more, to optimize some queries - the Projections could be used.
But again, my suggestion could be correct only if I do understand your scenario correctly: the two entities were introduced only to reduce workload; but both target all rows in one table.
The mapping for the only class
<class name="Entity" table="ENTITY" lazy="true">
<id name="ID" column="Entityd">
<generator class="native"></generator>
</id>
<!-- standard default always loaded properties -->
<property name="Code" />
<property name="Name" />
<!-- only if accessed, lazily loaded properties -->
<many-to-one lazy="proxy" name="Currency" column="CurrencyId" cascade="none" />
<property lazy="true" name="Image" column="ImageBinary" />
...
Having this mapping we can get first 5 Entities
var list = session.CreateCriteria<Entity>()
.SetMaxResults(5)
.List<Entity>();
And SQL statement generated will be:
SELECT TOP 5 this_.EntityId as EntityId3_1_
, this_.Code as Code3_1_
, this_.Name as Name3_1_
FROM ENTITY this_
And we can even reduce it with projections
var propertyList = NHibernate.Criterion.Projections.ProjectionList();
// projection properties
propertyList.Add(NHibernate.Criterion.Projections.Property("ID"));
propertyList.Add(NHibernate.Criterion.Projections.Property("Code"));
var projected = session.CreateCriteria<Entity>()
.SetMaxResults(5)
.SetProjection(propertyList)
.SetResultTransformer(new NHibernate.Transform
.AliasToBeanResultTransformer(typeof(Entity)))
.List<Entity>();
In this case is the SQL Select even smaller. If the ID and Code would be enough..
SELECT TOP 5 this_.Code as y0_
, this_.EntityId as y1_
FROM ENTITY this_
So, in case I read your question correctly, in your scenario solution would not be in inheritance but in NHibernate native laziness
NOTE: there could be ExtendedEntity derived from Entity even in this scenario. But not for inheritance via NHibernate mapping but for the Projections Transformation. Some properties from many-to-one properties could be projected this way...

"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!

How to avoid a join using NHibernate 2.1 per table inheritance

I'm doing some per table inheritance and all is working great- but I'm noticing that when I want the base entity (base table data) NHProf is showing a left outter join on the child entity / (related table)
How can I set the default behavior to only query the needed data - for example: When I want a list of parent elements (and only that data) the query only returns me that element.
right now my mapping is similar to the below:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="FormBase, ClassLibrary1" table="tbl_FormBase">
<id name="BaseID" column="ID" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<property name="ImportDate" column="ImportDate" type="datetime" not-null="false" />
<joined-subclass table="tbl_Form" name="Form, ClassLibrary1">
<key column="ID"/>
<property name="gendate" column="gendate" type="string" not-null="false" />
</joined-subclass>
</class>
</hibernate-mapping>
And the example where I want all the data back vs ONLY the parent entity is shown below:
Dim r As New FormRepository()
Dim forms As List(Of Form) = r.GetFormCollection().ToList()
Dim fbr As New FormBaseRepository()
Dim fb As List(Of FormBase) = fbr.GetFormBaseCollection().ToList()
You can't. It's called "implicit polymorphism" and it's a rather nice (albeit unwanted in your case :-) ) feature provided by Hibernate. When you query a list of base objects, the actual instances returned are of the actual concrete implementations. Hence the left join is needed for Hibernate to find out whether particular entity is a FormBase or a Form.
Update (too big to fit in comment):
The general issue here is that if you were to trick Hibernate into loading only the base entity you may end up with inconsistent session state. Consider the following:
Form instance (that is persisted to both form_base and form tables) was somehow loaded as FormBase.
You've deleted it.
During flush Hibernate (which thinks we're dealing with FormBase and thus is blissfully unaware that there are 2 tables involved) issues a DELETE FROM form statement which throws an exception as FK is violated.
Implicit polymorphism exists to prevent that from happening - Form is always a Form, never a FormBase. You could, of course, use "table-per-hierarchy" mapping where everything is in the same table and thus no joins are needed but you'll end up with (potentially) a lot of NULL columns and - ergo - inability to specify not-null on children's properties.
All that said, if this is REALLY a huge performance issue for you (which it normally shouldn't be - presumably it's an indexed join), you could try using a native query to just return FormBase instances.

Map a property to the latest entry in NHibernate

Let's say my domain looks like this:
I have an object, Vehicle, that has an OdometerReading property.
An OdometerReading has the Miles & Date (when it was read).
I need to keep a history of all OdometerReadings for the Vehicle in the database, but don't want the entire odometer history to belong to the Vehicle object. What I would like is for the OdometerReading property map to the most recent OdometerReading entry out of the database.
I thought about mapping the whole collection of OdometerReadings to the Vehicle, and having a dynamic property called CurrentOdometerReading that would order them and return the latest one, but I don't need the whole collection under the Vehicle in my domain, and it seems like I would be getting more data out of the database than I need.
Is that possible with NHibernate? How would I map such a thing?
There are a few ways of doing this depending on what you want your domain model to look like. My preferred choice is to use a custom collection type, for example IOdometerReadingCollection, which you can add extra methods to. In this case it might be something like:
public interface IOdometerReadingCollection : IList<OdometerReading>
{
OdometerReading Latest { get; }
}
This way you can do:
OdometerReading reading = vehicle.OdometerReadings.Latest;
which I prefer to:
OdometerReading reading = vehicle.LatestOdometerReading;
There's lots of documentation about custom collections, which you can find with a simple google search.
If this approach isn't for you there are other options. You may be able to use a property with a formula (I'm not sure if that works with complex types?), or a regular NHibernate association where you'd have the key of the latest OdometerReading on your Vehicle mapping. As you also mentioned you could just load all the OdometerReadings, which depending on your use case might actually be fine.
I hope this helps, or at least points you in the right direction.
There is a "where" clause that you can put in your collection mapping. Check the reference documentation.
I would map the OdometerReading property as a component, then use a named query to ensure it's populated with the latest reading out of the database. (In this example, you'd have a sql-query with a name of "vehicle" that does the SQL to load the Vehicle columns along with the latest Odometer reading)
<class name="Vehicle">
<property name="Type" not-null="true"/>
<component name="OdometerReading">
<property name="Miles" />
<property name="Date" />
</component>
<loader query-ref="vehicle"/>
</class>