I am porting over an application to NHibernate, but I'm running into a snag. The app's object structure is categorized into regular CRUDable objects, and static, read-only objects (ie. "lookups"). The lookups are loaded from the database once into a set of hashtables when the application starts.
The CRUDable objects sometimes reference the lookup data in one-to-one, or one-to-many relationships. Problems arise when I try to update the CRUDable objects with the references from the lookups/hashtables. On save, I receive "NHibernate.PropertyValueException: not-null property references a null or transient value". I suspect this is because the static read-only lookup reference in the global hashtable is not in the CRUDable object's session. When I fetched the lookup via the session in a limited test case, everything seemed to go smoothly. Am I correct that this is the case?
For a more concrete, if contrived, example:
Code:
public class Supplier {
int supplierId;
Country country;
//...getters/setters, etc.
}
//the following is a lookup
public class Country {
int countryId;
string name;
//...getters/setters, etc.
}
The mapping files:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" schema="dbo" default-access="field">
<class name="SpringAir.Objects.Supplier, SpringAir.Objects" table="Supplier">
<id name="supplierId" column="SupplierId" access="field" unsaved-value="-1">
<generator class="assigned" />
</id>
<many-to-one name="country" column="CountryId" not-null="true" cascade="none" />
</class>
<class name="SpringAir.Lookups.Country, SpringAir.Objects" table="Country" mutable="false">
<id name="countryId" type="Int32" column="CountryId">
<generator class="assigned" />
</id>
</class>
</hibernate-mapping>
A brief, contrived example of how it's used:
Code:
Supplier s = session.Load(typeof(Supplier), 1);
s.Country = countryTable[ this.lstCountries.SelectedItem.Value ]; //lookup the country based on a drop down selection
session.SaveOrUpdate(s);
session.Flush(); //<-- "NHibernate.PropertyValueException: not-null property references a null or transient value"
Unfortunately, I simply can't do away with the lookups at the moment, as it's deeply embedded in a great deal of code. If there's a way around this, I'd love to hear it!
If not, I've considered a few possible solutions, and I'd like some comments or pointers if it's not too much trouble:
- Upon opening a new session, iterate over all lookups and dump them into the session. This is infeasible because there are lookups with tens of thousands of records and sessions are created very frequently (ASP.NET).
- Adding some functionality so that NHibernate will query/reference the lookup tables instead of going to the database when loading these objects. Ways to do this:
- I'm not familiar with NHibernate internals, but I noticed the "class" has a "persister" attribute, which I believe references the NHibernate.Persister.IClassPersister interface. I'd investigate this avenue further, but it looks rather complicated, so I'd thought I'd solicit some opinions before investing the time.
- It just occured to me that the lookups can perhaps be viewed as a global cache of all of the lookup objects; might this avenue work? This cache must ONLY work for the lookup objects (ie. not the CRUDable objects). All lookups inherit from LookupBase which merely provides the scaffolding necessary to query the hastables based on given parameters.
Any thoughts and time-saving advice are much appreciated. :-)