Map a property to the latest entry in NHibernate - 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>

Related

how to persist a String/Object array such that indices and values are stored into separate columns in eclipselink

Am using EclipseLink 2.4.2 with derby database. I have an Entity class which has a String array. Now, i need to map this array to a separate table 'MY_ARGS' such that index must be mapped to one column 'ARRAY_INDEX' and the value (at index) must be mapped to another column 'ARG'.
In hibernate we have 'array' element through which we can do this. Like below :
<array name="args" table="MY_ARGS" cascade="all">
<key column="PARENT_ID"/>
<list-index column="ARRAY_INDEX" />
<element type="string" column="ARG" length="16384" />
</array>
But in eclipse-link am not able to find any such element (am using eclipselink-orm.xml) through which i can achieve this!
Does Eclipselink support such array to table(multi-column) mapping?
I read about #Converter through which we can convert the data type while storing to/retrieving from DB. But it looks like converter deals with single column and cannot store to two columns simultaneously.
Is there a way that i can do this through converter or any such work around? (I prefer not to use collections)
Any quick help is greatly appreciated!
Thanks in Advance!
-Alekhya

NHibernate mapping customization

I'm using Nhibernate 3.3.1 and I need to ensure that none of my string columns would have lengths smaller than 15 i.e.
I'm trying to check it no AfterMapProperty/BeforeMapProperty events of ModelMapper, but as I know Length property is private of PropertyMapper class or some base class of it.
I'm tryign to avoid to use Reflection to access private property to get Length and check it.
Can you help me?
You can use the check attribute to achieve this.. In your mapping file you need to define something like this:
<property name="Foo" type="string">
<column name="foo" check="DATALENGTH(foo) > 15"/>
</property>
This will create a check constraint.. I am not too sure about the DATALENGTH method but you can confirm that..
Refer section 20.1.1 of NH docs here: http://nhibernate.info/doc/nh/en/index.html

Querying by property of mapped subclass in 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!

NHibernate setting access="field.camelcase-underscore" fails in version 3

I have a solution that was created with NHib 1.2 which we're upgrading to NHib 3.0.
Our hbm file has the following property:
<property name="ContentId" column="ContentId" access="field.camelcase-underscore" />
The class doesn't have a ContentId property. This was working fine in NHib 1.2 but now we're getting getting the following exception:
Could not compile the mapping document: XXXX.Core.Domain.Video.hbm.xml ---> NHibernate.MappingException: Problem trying to set property type by reflection ---> NHibernate.MappingException: class Core.Domain.Video, Core, Version=1.0.0.29283, Culture=neutral, PublicKeyToken=null not found while looking for property: ContentId ---> NHibernate.PropertyNotFoundException: Could not find the property 'ContentId', associated to the field '_contentId', in class 'Core.Domain.Video'.
Why would this stop working? Is it still supported in NHib 3?
We have many many properties like this that we might need to add.
NHibernate greatly improved its error messaging and diagnostics in NH2.X and again in NH3.X. You are telling NHibernate that you have a property and you want to map it via field access to a field named by _camelCase convention. You don't have a property named ContentId and NHibernate is letting you know that you lied to it. :)
Try updating your mapping to:
<property name="_contentId" column="ContentId" access="field" />
You will need to update any HQL or Criteria queries to use _contentId rather than ContentId. Another option would be to add a private ContentId property.
I'd like to provide information which helped me answer this question:
http://groups.google.com/group/nhusers/browse_thread/thread/e078734a221c3c0c/ec8b873b385d4426?lnk=gst&q=field+camelcase+underscore#ec8b873b385d4426
In this link Fabio explains the same problem you are having like this:
This mapping
<property name="PositiveValue" access="field.camelcase-underscore" />
mean: For my property named "PositiveValue" you (NH) have to access to
the field; to discover which is the associated field you (NH) have to
use the strategy "camelcase-underscore".
If there is no property you can't use the accessor with a specific
strategy.
Which struck me as a little odd because it meant adding dummy, unused properties, just to make the nhibernate3 compiler happy. The underlying functionality is the same.

NHibernate Parent/Child Orphaned Records with Web Service

I have a web service that accepts an Invoice, which contains LineItem children. It then updates the database to either create or update the Invoice using NHibernate.
When an invoice is updated, it is passed to the web service along with all LineItem children it now has. Adds and updates work perfectly. However, if a child LineItem is deleted from a previously persisted Invoice by the Web Service consumer and re-submitted, that LineItem is not actually removed from the database, but rather it's back reference to the parent is set to NULL. I am using (trying to use) cascade="all-delete-orphan" without success.
I suspect that the problem might be due to the stateless nature of the operation (I don't first have the LineItem in Invoice.LineItemList on the web service side and then delete it, but rather just get a list of LineItem's as they now should be). However, NHibernate IS smart enough to null the back-reference column, so I hope there's a straightforward way to get it to delete that row instead.
Here are the mappings (simplified).
Parent object (Invoice):
<property name="InvoiceNumber" />
<!-- If inverse="true", InvoiceId is NOT set to NULL and the record remains -->
<bag name="LineItemList" table="lineitems" inverse="false" cascade="all-delete-orphan">
<key column="InvoiceId"/>
<one-to-many
class="LineItem"/>
</bag>
Child Objects (LineItems):
<many-to-one lazy="false" name="Parent" column="InvoiceID" not-null="false"
class="Invoice,Company.Business"
/>
<property name="LineItemNumber" />
<property name="SalesAmount"/>
The Web Service persistence code looks like this:
[WebMethod]
public Invoice PutInvoice(Invoice invoice)
{
// Necessary to rebuild parent references, see Blog
foreach (LineItem item in invoice.LineItems)
{
item.Parent = invoice;
}
using (PersistenceManager pm = new PersistenceManager())
{
pm.Save<Invoice>(invoice);
}
return invoice; // Return version potentially modified with DB-assigned ID
}
You are right this has to to with the detached state of your objects and is a known limitation in admission to performance which NHibernate describes as the not implemented feature of 'persistence of reachability'. However you could of course easily delete all LineItems without valid invoice reference but i also don't like this solution.
Usually i use client objects to achieve statelessness which of course results in loading the invoice before manipulating.