I am having issues assigning a reference to a subclass, for a joined-subclass mapped class. Basically, I can never cast it from a superclass reference. What is the recommended practice for using joined-subclass mapping classes polymorphically, if I cannot use the
as or
is operators?
Below follows a description of the issue:
In some test code, I am modelling a financial transaction, involving a financial security. To this effect, I have a Transaction class, and it has a Security property.
Now, a Security can either be a generic Security, or a more specific Option, which inherits from Security. I have a joined-subclass mapping in my Security.hbm.xml for Option.
The schema for Securities is two tables, Security and Option. Option has a foreign key SecurityId that maps to the Id column in the Security table.
The problem is that NHibernate retrieves the Transaction object and it's contained Security but, in the second line below, always returns null for a cast to Option, even if the Security is in fact an Option...
Code:
...
// Create an Option, assign to Transaction object, and SaveAndPersist.
...
IList<Transaction> trans = FindAll<Transaction>();
Option option = trans[0].Security as Option; // option is always inexplicably null
...
public ReadOnlyCollection<T> FindAll<T>(params ICriterion[] criterions)
{
ICriteria criteria = _session.CreateCriteria(typeof (T));
foreach (ICriterion criterion in criterions)
{
criteria.Add(criterion);
}
List<T> list = new List<T>();
foreach (object o in criteria.List())
list.Add((T) o);
return list.AsReadOnly();
}
The problem is that NHibernate wraps the Security object in its proxy class, in this case of type
CProxyTypeNextWorks_DomainModel_Security_NHibernate_ProxyINHibernateProxy1. Now, as the base class of the proxy is Security, this proxy is obviously fine to assign to the Transaction.Security property, but I cannot ever cast this back to an Option. In the Watch panel in Visual Studio 2005, I can see that the value of the Security is an Option, but I cannot cast to an option because of the Proxy wrapping (or so I believe).
I have run SQL Profiler and NHibernate is joining the tables correctly in the query.
What is the recommended practice for using joined-subclass mapping classes polymorphically, if I cannot use the
as or
is operators?
Version and mapping documents below.
Hibernate version: 1.2.0.2002
Mapping documents:Code:
Security
=========
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NextWorks.DomainModel" namespace="NextWorks.DomainModel"
default-access="field.camelcase-underscore">
<class name="Security" table="Security">
<id name="ID" column="id" type="Int32" unsaved-value="0" access="field.lowercase-underscore">
<generator class="identity" />
</id>
<property name="Name" />
<many-to-one name="StockExchange" class="NextWorks.DomainModel.StockExchange" column="StockExchangeID"
not-null="true"/>
<bag name="Transactions"
inverse="true">
<key column="SecurityID"/>
<one-to-many class="Transaction"/>
</bag>
</class>
<joined-subclass name="Option" table="Option" extends="NextWorks.DomainModel.Security">
<key column="SecurityId" />
<property name="Type" />
<property name="MaturityDate" />
<property name="ExercisePrice" />
<property name="ContractSize" />
</joined-subclass>
</hibernate-mapping>
Code:
Transaction
===========
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NextWorks.DomainModel" namespace="NextWorks.DomainModel"
default-access="field.camelcase-underscore">
<class name="Transaction" table="Transaction">
<id name="ID" column="id" type="Int32" unsaved-value="0" access="field.lowercase-underscore">
<generator class="identity" />
</id>
<property name="ProcessingDate" />
<property name="Type" />
<property name="Quantity" />
<property name="BrokerFee" />
<property name="ClearingFee" />
<property name="CommissionFee" />
<property name="TransactionPrice" />
<property name="TransactionDate" access="field.camelcase-underscore" />
<property name="EffectiveValue" access="field.camelcase-underscore" />
<many-to-one name="Security" class="Security" column="SecurityID"
not-null="true"/>
<many-to-one name="Account" class="Account" column="AccountID"
not-null="true" />
<many-to-one name="Currency" class="NextWorks.DomainModel.Currency" column="CurrencyID"
not-null="true" />
</class>
</hibernate-mapping>