Search code examples
nhibernatefluent-nhibernatenhibernate-mappingfluent-nhibernate-mapping

Fluent NHibernate mapping protected properties: could not resolve property: BookingNumber of: B


Assume the following classes:

public class A
{
  public virtual ind Id { get; set; }
  public virtual int Number { get; protected set; }
}

public class B : A
{
  public virtual string SomeValue { get; set; }

  public virtual int BookingNumber
  {
    get { return Number; }
    set { Number = value; }
  }
}

public class C : A
{
  public virtual string SomeOtherValue { get; set; }

  public virtual int AccountNumber
  {
    get { return Number; }
    set { Number = value; }
  }
}

As you can see I want to expose the property Number under different names.

Now I want to map A, B, C.

public class AMap : ClassMap<A>
{
  public AMap()
  {
    Id(x => x.Id);
    Map(x => x.Number);
  }
}

public class BMap : SubclassMap<B>
{
  public BMap()
  {
    Map(x => x.SomeValue);
  }
}

public class CMap : SubclassMap<C>
{
  public CMap()
  {
    Map(x => x.SomeOtherValue);
  }
}

With this mapping I can save stuff to the database.

However when I query B or C:

Session.QueryOver<B>().Where(x => x.BookingNumber).List();

I receive the error could not resolve property: BookingNumber of: B

What am I doing wrong?


Solution

  • What is wrong? To build query on unmapped properties.

    (wrapping base properties in derrived classes with DIFFERENT names is at least strange), If this approach is really needed because some upper layers need diffrent names for the same property... then, well, ok. But, NHibernate must be provided with different set of information.

    Think about your query, as self descriptive information, containing enough to be converted to SQL statement.

    So if you use QueryOver<B>.Where(x => x.BookingNumber == 1).... the information is (when parsing lambda expressions):

    1. Work with C# object B,
    2. find its property BookingNumber,
    3. find its mapped representation: column name BookingNumberColumn,
    4. take the value: 1 and
    5. built a query WHERE BookingNumberColumn = 1

    In this case, the step number 3 fails. No column is mapped to BookingNumber...

    Solution is, at least on Data (NHibernate) layer, apply filter based on a base class A mapping

    Session
      .QueryOver<B>()
      .Where(x => x.Number == 1) // use the A.Number MAPPED property
      .List<B>();
    

    BUT, based on my experience, what we are mostly doing, is the conversion of differences in persistance (different id column name, different code column) and map them to the C# base class or interface with common, simplified structure.

    More here: 16. QueryOver Queries