R – Using a Join and Component together in Fluent NHibernate Mapping throws “Could not find a getter for property exception”

fluent-nhibernatenhibernatenhibernate-mapping

Using a Join and Component together in Fluent NHibernate Mapping throws "Could not find a getter for property exception". This is my C# code

using FluentNHibernate.Mapping;

namespace FnhTest {
    public class CustomerMap : ClassMap<Customer> {
        public CustomerMap() {
            Id(x => x.Id).GeneratedBy.Identity();
            Map(x => x.Name);

            Join("BillingInfo", m =>
                               {
                                   m.KeyColumn("CustomerId");
                                   m.Component(x => x.BillingInfo, c =>
                                                                   {
                                                                       c.Map(y => y.AccountNumber);
                                                                       c.Map(y => y.Address);
                                                                   });
                               });
        }
    }

    public class BillingInfo {
        public virtual string AccountNumber { get; set; }
        public virtual string Address { get; set; }
    }

    public class Customer {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }

        public virtual BillingInfo BillingInfo { get; set; }
    }
}

And this is my Database structure =>

Customers:
  Id (int)
  Name (varchar 50)
BillingInfo:
  Id (int)
  AccountNumber (varchar 50)
  Address (varchar 50)
  CustomerId (int) (Foriegn Key to the Customers Id)

Fluent NHibernate generates the right mapping for this setup, but for some reason it throws up an error. Given below are the mapping and the error

Mapping:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="FnhTest.Customer, FnhTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Customer`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <property name="Name" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Name" />
    </property>
    <join table="BillingInfo">
      <key>
        <column name="CustomerId" />
      </key>
      <component name="BillingInfo" insert="true" update="true" optimistic-lock="true">
        <property name="AccountNumber" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
          <column name="AccountNumber" />
        </property>
        <property name="Address" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
          <column name="Address" />
        </property>
      </component>
    </join>
  </class>
</hibernate-mapping>

Error:

TestCase 'M:FnhTest.Program.Main(System.String[])'
failed: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

  * Database was not configured through Database method.

    FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

      * Database was not configured through Database method.
     ---> NHibernate.PropertyNotFoundException: Could not find a getter for property 'AccountNumber' in class 'FnhTest.Customer'
    at NHibernate.Properties.BasicPropertyAccessor.GetGetter(Type type, String propertyName)
    at NHibernate.Tuple.Component.PocoComponentTuplizer.BuildGetter(Component component, Property prop)
    at NHibernate.Tuple.Component.AbstractComponentTuplizer..ctor(Component component)
    at NHibernate.Tuple.Component.PocoComponentTuplizer..ctor(Component component)
    at NHibernate.Tuple.Component.ComponentEntityModeToTuplizerMapping..ctor(Component component)
    at NHibernate.Tuple.Component.ComponentMetamodel..ctor(Component component)
    at NHibernate.Mapping.Component.BuildType()
    at NHibernate.Mapping.Component.get_Type()
    at NHibernate.Mapping.SimpleValue.IsValid(IMapping mapping)
    at NHibernate.Mapping.PersistentClass.Validate(IMapping mapping)
    at NHibernate.Mapping.RootClass.Validate(IMapping mapping)
    at NHibernate.Cfg.Configuration.Validate()
    at NHibernate.Cfg.Configuration.BuildSessionFactory()
    d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs(93,0): at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
       --- End of inner exception stack trace ---
    d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs(100,0): at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
    D:\repositories\core\playground\minhajuddin\FnhTest\FnhTest\Program.cs(8,0): at FnhTest.Program.Main(String[] args)

      * Database was not configured through Database method.


0 passed, 1 failed, 0 skipped, took 6.46 seconds (Ad hoc).

I've searched all over the web but was unable to find anything helpful, Any kind of help would be greatly appreciated 🙂

EDIT:
Well, I didn't find a way to do this in Fluent NHibernate, I am using whatever Torkel has posted as an answer. But, that was not my intention. Anyway.

Best Answer

BillingInfo looks to me not like a component but an entity.

If you map BillingInfo as an entity you can map it from Customer as a association.

<many-to-one name="BillingInfo" property-ref="CustomerId" cascade="none"/>

The property-ref is importand as you do not want to join on on the BillingInfo Id but on the CustomerId, this however requires you to add a CustomerId property to your BillingInfo class.

Related Topic