hibernate错误:entity 'ClassMap ' 1'没有映射的Id

本文关键字:映射 Id 错误 hibernate ClassMap entity | 更新日期: 2023-09-27 18:01:50

我正在将以前的项目从使用正常的NHibernate hbm.xml映射转换为流利的NHibernate。目前,我被困在什么应该是最后的步骤之一,让这个工作。我已经为DefaultAutomappingConfiguration添加了一个派生类来修改我的ID命名约定。字符串"Id"被附加到类名后面:

    public override bool IsId(FluentNHibernate.Member member)
    {
        return member.Name == member.DeclaringType.Name + "Id";
    }

这应该使"Agency"在名为"AgencyId"的字段中有一个ID。相反,我得到这个错误:

The entity 'ClassMap`1' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).
{Name = "ClassMap`1" FullName = "FluentNHibernate.Mapping.ClassMap`1[[BackendDb.Model.Agency, BackendDb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}

我在IsId函数上设置了一个断点,看看发生了什么:

{Property: Cache}
{Name = "ClassMap`1" FullName = "FluentNHibernate.Mapping.ClassMap`1[[BackendDb.Model.Agency, BackendDb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}

这是什么?对象不是我创造的东西。其他所有对象都可以很好地通过这个函数,而我真正想要映射的对象都返回了正确的值。

我的会话工厂看起来像这样:

var cfg = new MapConfig();
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(m => m.Server(@".'SqlExpress")
    .Database("{some dbname}")
    .TrustedConnection()))
.Mappings(m =>
    m.AutoMappings
        .Add(AutoMap.AssemblyOf<Agency>(cfg))
)
.BuildSessionFactory();

令人恼火的是,似乎这在某种程度上导致了我在开发数据库中测试Fluent NHibernate的三个表被清空。搞什么鬼?

hibernate错误:entity 'ClassMap ' 1'没有映射的Id

sessionfactory正在尝试自动映射程序集中包含您的Agency类的所有类,基于此指令:Add(AutoMap.AssemblyOf<Agency>(cfg))。由于程序集中有AgencyMap,而ClassMap<>没有Id属性,因此FNH抛出错误。

如果你想使用ClassMap<>配置,而不是声明一个自动映射配置,声明一个流畅的映射:

m.FluentMappings.AddFromAssemblyOf<Agency>();

如果你不需要automapping,删除' . automapping。添加的指令。

然而,如果你想使用automapping,你需要告诉FNH你想映射什么类。为了处理这个问题,我通常定义一个标记接口:

public abstract class Entity : IPersistable
{
    public virtual int Id { get; set; }
}
public interface IPersistable
{
}

然后,在我从DefaultAutomappingConfiguration派生的类中,我告诉FNH只映射具有该接口的类(您可以限制映射的类,但您认为合适):

public class EntityAutoMappingConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type.GetInterfaces().Contains(typeof (IPersistable));
    }
}
为了处理主键映射,我创建了一个约定类:
public class PrimaryKeyNamePlusId : IIdConvention 
{
    public void Apply(IIdentityInstance instance)
    {
        instance.Column(instance.EntityType.Name+"Id");
    }
}

最后,我配置我的SessionFactory使用配置/约定类:

 m.AutoMappings.AssemblyOf<Entity>(new EntityAutoMappingConfiguration())
            .IgnoreBase<Entity>()
            .UseOverridesFromAssemblyOf<Entity>()
            .Conventions.AddFromAssemblyOf<Entity>();

您不能将ClassMap与自动器结合使用,除非您还配置自动器以忽略您正在使用ClassMap的实体及其各自的映射文件。

在我的情况下,我碰巧使用自定义属性来指示应该被自动映射的类,所以我可以扔掉各种我不想映射到我的.dll中的垃圾,而不需要Fluent尝试自动映射它:

/// <summary>
/// Add this attribute to entity classes which should be automapped by Fluent.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
class AutomapAttribute : Attribute
{
}

在我的DefaultAutomappingConfiguration覆盖类:

    public override bool ShouldMap(Type type)
    {
        return (type.Namespace == "Data.Entities" 
            && type.GetCustomAttributes(typeof(AutomapAttribute), false).Length > 0);
    }

当然,如果您只是将自动映射的实体保存在与其他类不同的名称空间中,则不需要检查属性。