NHibernate“无法确定 X 的类型”错误

Posted

技术标签:

【中文标题】NHibernate“无法确定 X 的类型”错误【英文标题】:NHibernate "Could not determine type for X" error 【发布时间】:2011-06-29 23:49:28 【问题描述】:

在项目中升级 NHibernate 和 FluentNHibernate DLL 后,我现在在初始化 SessionFactory 时出现“无法确定类型:MyApp.Domain.Entities.AppCategory”异常。我的代码中唯一的变化是调整 ForeignKeyConvention 的实现以覆盖 GetKeyName ( Member member, Type type ) 抽象方法,而不是 GetKeyName ( PropertyInfo property, Type type )

对于 FluentNHibernate,升级后的 DLL 从 1.0.0.593 到 1.1.0.685,对于 NHibernate 从 2.1.0.4000 到 2.1.2.4000。找到解决方案的部分困难在于我们使用的 NHibernate 版本已经过时,但至少目前无法改变。

我在下面发布了完整的异常以及所有相关代码和配置。对于篇幅较长,我深表歉意,但我不知道问题可能出在哪里。

完全例外

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) 

流畅的配置

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";
    

域类

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; 

数据库表定义

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)
)

流畅的 NHibernate 映射

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));
    

映射 XML(从 Fluent NHibernate 日志消息中提取):

<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>

【问题讨论】:

【参考方案1】:

也许为时已晚,但您仍然会对我找到的解决方案感兴趣。当我试图覆盖我的一个实体的映射时,我遇到了同样的问题。

此错误的典型原因是当您尝试为复杂类型调用 Map() 时。在这种情况下,Fluent NHibernate 试图找出该实体的类型以映射到相应的数据库类型(例如,intintegerboolbit 等)并且只要没有这样的对应关系对于 AppCategory 类型,它失败了。

因此,如果您更改以下行,您的错误可能会得到解决

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

到这个

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

【讨论】:

这就是确切的原因。感谢您提出正确的解决方案。

以上是关于NHibernate“无法确定 X 的类型”错误的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate 3.3.1 与中等信任错误

这个错误在 nhibernate 中是啥意思

错误的连接字符串NHibernate 3.3

nhibernate中的命名查询错误

NHibernate - 错误脱水属性值 - 更新实体

NHibernate 错误