Search code examples
oopnhibernatenhibernate-mapping

NHibernate could not resolve property of an inherited property


Why can't NHibernate access a property inherited from an abstract base class. When I try to use the property in a QueryOver in the Where clause I'm getting

could not resolve property: ID of: TheWorkshop.Web.Models.Customer

var customer = Session.QueryOver<Customer>()
                      .Where(c=>c.ID ==id)
                      .SingleOrDefault<Customer>();

Intelisense helped me build the query and the solution compiles, so there is an ID property on the Customer class. The ID property on Customer is inherited from an abstract Contact class that in turn inherits from a DomainEntity<T> which exposes a protected field.

public abstract class DomainEntity<T>
{
    protected Guid _persistenceId;
    //... 
}

public abstract class Contact : DomainEntity<Contact>
{
    public virtual Guid ID
    {
        get { return _persistenceId; }
    }

    public virtual Address Address
    {
        get { return _address; }
        set { _address = value; }
    }

    //... 
}

and in the mapping file

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
                   assembly="TheWorkshop.Web" 
                   namespace="TheWorkshop.Web.Models" 
                   default-access="field.camelcase-underscore" 
                   default-lazy="true">
    <class name="Contact" table="Contacts" abstract="true">
        <id name="_persistenceId" column="ID" type="Guid" access="field" 
            unsaved-value="00000000-0000-0000-0000-000000000000">
        <generator class="guid.comb" />
        </id>
        <!-- ... -->
        <union-subclass name="Customer" table="Customers">

Following the answer to a similar question I updated to NHibernate 3.3.3-CR1 from NHibernate 3.3.2.4000 but I still have the same issue.


Solution

  • The problem was that NHibernate couldn't infer from my mapping how to resolve the ID property. So although the classes compiled fine and the _persistenceId property on the abstract base class could be accessed through a getter on the implementing classes, because of the mismatch in names between _persistenceId and ID NHibernate wasn't able to follow that.

    The (easier) solution was to change my names to match up. There is a harder solution which involves implementing the IProperyAccessor, IGetter and ISetter interfaces and in order to provide a path to pass the string ID in order to use the ClassName access strategy.

    The simpler of the two solutions was just to rename _persistenceId to _id (and update all the references to it) so

    <id name="_persistenceId" column="ID" type="Guid" access="field" 
        unsaved-value="00000000-0000-0000-0000-000000000000">
    

    becomes

    <id name="Id" column="Id" type="Guid" 
        unsaved-value="00000000-0000-0000-0000-000000000000">
    

    Note I was also able to drop the access="field" in the updated id mappings