我目前正在深入研究NHibernate,目前正在研究自动化功能与Fluent NHibernate的显式流畅api ClassMap配置之间的细微差别。我有以下设置:
public abstract class AuditableEntity : IAuditableEntity
{
public virtual DateTime CreateDate { get; set; }
public virtual DateTime? EditDate { get; set; }
}
public abstract class Entity<TKey> : AuditableEntity where TKey : struct
{
public virtual TKey Id { get; protected set; }
}
一些派生域实体遵循与下面实体类似的结构:
public class Brochure : Base.Entity<Int32>
{
public Brochure()
{
Menus = new HashSet<Menu>();
}
public virtual string Title { get; set; }
public virtual string Description { get; set; }
public virtual ISet<Menu> Menus { get; protected set; }
public virtual void AddMenu(Menu menu)
{
menu.Brochure = this;
this.Menus.Add(menu);
}
}
当使用显式的流畅api映射时,我能够对ClassMap类进行子类化并将其用作域实体映射的基类。这实际上提供了与EF MapInheritedProperties相同的功能,例如:
public class AuditMap<TEntity> : ClassMap<TEntity> where TEntity : AuditableEntity
{
public AuditMap()
{
this.Map(x => x.CreateDate);
this.Map(x => x.EditDate);
}
}
public class BrochureMap : BaseMaps.AuditMap<Brochure>
{
public BrochureMap()
{
this.Id(x => x.Id).Not.Nullable().Column("BrochureId").GeneratedBy.HiLo("9");
this.Map(x => x.Title).Length(50).Not.Nullable();
this.Map(x => x.Description).Length(250).Nullable();
this.HasMany(b => b.Menus).LazyLoad()
.AsSet()
.KeyColumn("BrochureId")
.ForeignKeyConstraintName("BrochureId")
.Cascade.All();
}
}
然而,我无法通过内置约定或实现自定义约定来使用流畅的nhibernate自动化api来找到如何实现此目的的明确方法,这些约定在其功能集中也受到限制
我目前的流畅和自动化配置如下所示:
try
{
ISessionFactory sessionFactory =
Fluently.Configure()
.Database(() =>
{
return MsSqlConfiguration.MsSql2012.ConnectionString(c => c.FromConnectionStringWithKey("QuickSnacksDb"))
.Dialect<MsSql2012Dialect>()
.Driver<SqlClientDriver>();
})
.Mappings(m =>
{
m.AutoMappings.Add(CustomAutomappings);
m.FluentMappings.AddFromAssemblyOf<BrochureMap>()
.Conventions.Setup(c =>
{
c.Add(ForeignKey.EndsWith("Id"));
});
})
.ExposeConfiguration(cfg =>
{
cfg.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { new AuditingEventListener() };
cfg.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { new AuditingEventListener() };
})
.BuildSessionFactory();
return sessionFactory;
}
catch(FluentConfigurationException e)
{
}
以下是自动配置api ...使用的组件
private static AutoPersistenceModel CustomAutomappings()
{
return AutoMap.AssemblyOf<Brochure>(new AutoMappingConfiguration())
.Conventions.Setup(c =>
{
c.Add<TableNameConvention>();
})
.IgnoreBase(typeof(Entity<>))
.IncludeBase<AuditableEntity>();
}
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table("[dbo].[" + instance.EntityType.Name + "s]");
}
}
public class AutoMappingConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
string typeNamespace = type.Namespace;
bool mapType = typeNamespace == "QuickSnacks.Data.NHibernate.Entities" || typeNamespace == "QuickSnacks.Data.NHibernate.Entities.Components";
return mapType;
}
public override bool IsComponent(Type type)
{
bool mapComponent = type == typeof(AuditInfo);
return mapComponent;
}
}
我理解这在审计支持方面是一个小细节,但它让我想知道我能够在多大程度上拦截映射管道并在基类或派生子上添加/覆盖属性类。
另外,考虑到nhibernate的年龄和成熟度,我遇到的许多参考文献(主要是博客和文章)分散,范围有限或仅仅过时。在Read the Docs这样的平台上对nhibernate及其相关项目进行全面修订将会非常方便和有帮助,但要完全理解这本身就是一项艰巨的任务。
非常感谢在高级场景中使用fluent-nhibernate映射api的任何提示,链接或指示。