C# – NHibernate “Could not determine type for X” error

cfluent-nhibernatenhibernate

After upgrading the NHibernate and FluentNHibernate DLLs in a project, I'm now getting a "Could not determine type for: MyApp.Domain.Entities.AppCategory" exception thrown when initializing the SessionFactory. The only change in my code was tweaking the implementation of ForeignKeyConvention to override the GetKeyName ( Member member, Type type ) abstract method, instead of GetKeyName ( PropertyInfo property, Type type ).

The upgraded DLLs were from 1.0.0.593 to 1.1.0.685 for FluentNHibernate, and from 2.1.0.4000 to 2.1.2.4000 for NHibernate. Part of the difficulty in finding a solution is the old age of the NHibernate version we're using, but that can't be changed, at least for now.

I posted the full exception and all relevant code and configuration below. I apologize for the length, but I have no idea where the problem might be.

Full Exception

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

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

  ----> NHibernate.MappingException : Could not compile the mapping document: (XmlDocument)
  ----> NHibernate.MappingException : Could not determine type for: MyApp.Domain.Entities.AppCategory, MyApp.Domain, Version=1.0.0.76, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(AppCategory)
at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs: line 98
at MyFramework.App.DataAccess.NHibernate.Databases.BaseDatabase.CreateSessionFactory() in C:\WIP\VSProjects\MyFramework\src\App\DataAccess\NHibernate\Databases\BaseDatabase.cs: line 115
at MyFramework.App.DataAccess.NHibernate.Databases.BaseDatabase.Init() in C:\WIP\VSProjects\MyFramework\src\App\DataAccess\NHibernate\Databases\BaseDatabase.cs: line 100
at MyApp.DataAccess.SmartStudioUserUnitOfWork.<.ctor>b__0() in SmartStudioUserUnitOfWork.cs: line 28
at MyFramework.App.DataAccess.NHibernate.UnitOfWork`1.Create(FlushMode flushMode) in C:\WIP\VSProjects\MyFramework\src\App\DataAccess\NHibernate\UnitOfWork.cs: line 72
at MyFramework.App.DataAccess.NHibernate.UnitOfWork`1..ctor(Func`1 getBaseDatabase) in C:\WIP\VSProjects\MyFramework\src\App\DataAccess\NHibernate\UnitOfWork.cs: line 37
at MyApp.DataAccess.SmartStudioUserUnitOfWork..ctor() in SmartStudioUserUnitOfWork.cs: line 17
at MyApp.DataAccess.Test.SmartStudioUserDaoTest.create_dao() in SmartStudioUserDaoTest.cs: line 20
--FluentConfigurationException
at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration() in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs: line 119
at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs: line 93
--MappingException
at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception)
at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc)
at NHibernate.Cfg.Configuration.ProcessMappingsQueue()
at NHibernate.Cfg.Configuration.AddDocumentThroughQueue(NamedXmlDocument document)
at NHibernate.Cfg.Configuration.AddXmlReader(XmlReader hbmReader, String name)
at NHibernate.Cfg.Configuration.AddInputStream(Stream xmlInputStream, String name)
at NHibernate.Cfg.Configuration.AddDocument(XmlDocument doc, String name)
at NHibernate.Cfg.Configuration.AddDocument(XmlDocument doc)
at FluentNHibernate.PersistenceModel.Configure(Configuration cfg) in d:\Builds\FluentNH\src\FluentNHibernate\PersistenceModel.cs: line 262
at FluentNHibernate.Automapping.AutoPersistenceModel.Configure(Configuration configuration) in d:\Builds\FluentNH\src\FluentNHibernate\Automapping\AutoPersistenceModel.cs: line 170
at FluentNHibernate.Cfg.AutoMappingsContainer.Apply(Configuration cfg) in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\AutoMappingsContainer.cs: line 84
at FluentNHibernate.Cfg.MappingConfiguration.Apply(Configuration cfg) in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\MappingConfiguration.cs: line 56
at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration() in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs: line 110
--MappingException
at NHibernate.Mapping.SimpleValue.get_Type()
at NHibernate.Cfg.XmlHbmBinding.ClassBinder.BindProperty(XmlNode node, Property property, IDictionary`2 inheritedMetas)
at NHibernate.Cfg.XmlHbmBinding.ClassBinder.CreateProperty(IValue value, String propertyName, String className, XmlNode subnode, IDictionary`2 inheritedMetas)
at NHibernate.Cfg.XmlHbmBinding.ClassBinder.BindJoin(XmlNode node, Join join, IDictionary`2 inheritedMetas)
at NHibernate.Cfg.XmlHbmBinding.ClassBinder.PropertiesFromXML(XmlNode node, PersistentClass model, IDictionary`2 inheritedMetas, UniqueKey uniqueKey, Boolean mutable, Boolean nullable, Boolean naturalId)
at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.Bind(XmlNode node, HbmClass classSchema, IDictionary`2 inheritedMetas)
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddRootClasses(XmlNode parentNode, IDictionary`2 inheritedMetas)
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(XmlNode node)
at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc) 

Fluent Configuration

sessionFactory = fluentConfiguration
    .Mappings(m => m.AutoMappings.Add(
        AutoMap.AssemblyOf<Application>().Conventions
            .Add<CustomForeignKeyConvention>()))
    .ExposeConfiguration(new SchemaExport(config).Create(true, false))
    .BuildSessionFactory();

public class CustomForeignKeyConvention : ForeignKeyConvention
{
    protected override string GetKeyName ( Member member, Type type )
    {
        if (member == null)
        {
            return type.Name + "Id";
        }

        return member.Name + "Id";
    }
}

Domain classes

public class Application
{
    public virtual int Id { get; set; }
    public virtual string FriendlyName { get; set; }
    public virtual AppCategory AppCategory { get; set; }
}

public class AppCategory
{
    public virtual int Id { get; private set; }
    public virtual string CategoryName { get; set; }
}

Database Table Definitions

CREATE TABLE [dbo].[Application](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FriendlyName] [varchar](255) NOT NULL,
    [AppCategoryId] [int] NOT NULL,
    CONSTRAINT [PK_Application] PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
ALTER TABLE [dbo].[Application] WITH CHECK
        ADD CONSTRAINT [FK_Application_AppCategory] FOREIGN KEY([AppCategoryId])
        REFERENCES [dbo].[AppCategory] ([Id])
GO
ALTER TABLE [dbo].[Application] CHECK CONSTRAINT [FK_Application_AppCategory]
GO

CREATE TABLE [dbo].[AppCategory](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [CategoryName] [nvarchar](50) NOT NULL,
    CONSTRAINT [PK_AppCategory] PRIMARY KEY CLUSTERED ([Id] ASC)
)

Fluent NHibernate Mapping

public class ApplicationMappingOverride : IAutoMappingOverride<Application>
{
    public void Override(AutoMapping<Application> mapping)
    {
        mapping.Table("Application");
        mapping.Id(x => x.Id);
        mapping.Map(x => x.FriendlyName);
        mapping.Join("AppCategory", x => x.Map(y => y.AppCategory));
    }
}

Mapping XML (pulled from Fluent NHibernate log message):

<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" mutable="true"
        name="MyApp.Domain.Entities.Application, MyApp.Domain, Version=1.0.0.76, Culture=neutral, PublicKeyToken=null" table="Application">

        <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="FriendlyName" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
            <column name="FriendlyName" />
        </property>

        <join table="AppCategory">
            <key>
                <column name="ApplicationId" />
            </key>
            <property name="AppCategory" type="MyApp.Domain.Entities.AppCategory, MyApp.Domain, Version=1.0.0.76, Culture=neutral, PublicKeyToken=null">
                <column name="AppCategory" />
            </property>
        </join>

    </class>
</hibernate-mapping>

Best Answer

Maybe it is too late, but you will still be interested in the solution that I've found. I've faced the same problem when I was trying to override mappings for one of my entities.

The typical reason for this error is when you are trying to call Map() for the complex type. In this case Fluent NHibernate is trying to figure out the type of this entity to map to corresponding database type (e.g. int to integer, bool to bit, etc) and as far as there is no such correspondence for the AppCategory type it fails.

So your error will probably be fixed if you'll change following line

 mapping.Join("AppCategory", x => x.Map(y => y.AppCategory));

to this one

 mapping.Join("AppCategory", x => x.References(y => y.AppCategory));