我正在将之前的项目从使用普通的NHibernate hbm.xml映射转换为Fluent NHibernate。目前,我仍然坚持要实现这一目标的最后步骤之一。我为DefaultAutomappingConfiguration添加了一个派生类来修改我的ID命名约定。字符串“Id”附加到类名:
public override bool IsId(FluentNHibernate.Member member)
{
return member.Name == member.DeclaringType.Name + "Id";
}
这应该使“代理商”在名为“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]]"}
这是什么?对象不是我创造的东西。每个其他对象都可以很好地通过这个函数,而我实际想要映射的对象正在返回正确的值。
我的Session工厂看起来像这样:
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的三个表被清空。怎么了?
答案 0 :(得分:7)
sessionfactory正在尝试根据此指令自动执行包含Agency
类的程序集中的所有类:Add(AutoMap.AssemblyOf<Agency>(cfg))
。由于程序集中有AgencyMap
且ClassMap<>
没有Id
属性,因此FNH会抛出错误。
如果要使用ClassMap<>
配置,而不是(或除此之外)声明自动配置,请声明一个流畅的映射:
m.FluentMappings.AddFromAssemblyOf<Agency>();
如果您不需要AutoMappings,请删除`.AutoMappings.Add'指令。
但是,如果要使用AutoMappings,则需要告诉FNH要映射的类。为了解决这个问题,我通常会定义一个标记界面:
public abstract class Entity : IPersistable
{
public virtual int Id { get; set; }
}
public interface IPersistable
{
}
然后,在我从DefaultAutomappingConfiguration
派生的类中,我告诉FNH只映射具有该接口的类(您可以限制映射的类,但是您认为合适):</ p>
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>();
答案 1 :(得分:0)
您不能将ClassMap
与automapper结合使用,除非您还将automapper配置为忽略您正在使用ClassMap的Entites及其各自的映射文件。
在我的情况下,我碰巧使用自定义属性来指示应该自动化的类,所以我可以抛出我不希望映射到我的.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);
}
当然,如果只是将自动化实体保存在与其他类不同的命名空间中,则无需检查属性。