我认为这之前一定是问过,但是我用Google搜索了一个小时但找不到答案。
假设我有以下两种型号:
public class Organism
{
public virtual int Id { get; private set; }
}
public class Animal : Organism
{
}
我希望Fluent NHibernate为我创建以下表格:
OrganismTable
OrganismId
AnimalTable
AnimalId
这可以通过使用手动映射轻松实现:
public class OrganismMappinig : ClassMap<Organism>
{
public OrganismMappinig()
{
Table("OrganismTable");
Id(x => x.Id).Column("OrganismId");
}
}
public class AnimalMapping : SubclassMap<Animal>
{
public AnimalMapping()
{
Table("AnimalTable");
KeyColumn("AnimalId");
}
}
但是我无法使用自动化获得相同的结果。我尝试添加以下约定:
public class TableNameConvension : IClassConvention, IClassConventionAcceptance
{
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name + "Table");
}
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.TableName, Is.Not.Set);
}
}
public class PrimaryKeyNameConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
}
}
它创建了这两个表:
OrganismTable (correct)
OrganismId (correct)
Animal (wrong, should be "AnimalTable")
Organism_id (wrong, should be "AnimalId")
我也尝试添加:
public class ForeignKeyColumnNameConvention : ForeignKeyConvention
{
protected override string GetKeyName(Member property, Type type)
{
if (property == null)
return type.Name + "Id";
return property.Name + "Id";
}
}
它创建了这两个表:
OrganismTable (correct)
OrganismId (correct)
Animal (wrong, should be "AnimalTable")
OrganismId (wrong, should be "AnimalId")
我也尝试添加:
public class AnimalOverride : IAutoMappingOverride<Animal>
{
public void Override(AutoMapping<Animal> mapping)
{
mapping.Table("AnimalTable");
mapping.Id(x => x.Id).Column("AnimalId");
}
}
它创建了以下表格:
OrganismTable (correct)
OrganismId (correct)
AnimalTable (correct)
OrganismId (wrong, should be "AnimalId")
这正确地将表名设置为“AnimalTable”(但这需要太多的手动输入,如果有一个可以获得相同结果的约定,那将是很好的),但是未能将键列名设置为“AnimalId”。 / p>
以下是我的其余代码:
class Program
{
static void Main(string[] args)
{
ISessionFactory sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008.ConnectionString(connectionString)
.ShowSql())
.Mappings(m => m.AutoMappings.Add(
AutoMap.Assemblies(typeof(Organism).Assembly)
.Conventions.AddAssembly(typeof(Program).Assembly)
.UseOverridesFromAssembly(typeof(Program).Assembly)))
.ExposeConfiguration(BuildSchema)
.BuildConfiguration()
.BuildSessionFactory();
}
static void BuildSchema(Configuration cfg)
{
new SchemaExport(cfg).Create(false, true);
}
}
有什么想法吗?感谢。
答案 0 :(得分:8)
当FluentNHibernate自动化时,它使用table-per-concrete-class来映射继承层次结构。由于有机体和动物都是具体类型,它会生成两个表,OrganismTable和AnimalTable。 OrganismTable存储所有生物共有的所有属性。 AnimalTable仅存储Animal子类添加的属性。 AnimalTable上的PK也是OrganismTable的FK。因此它会受到你的FK大会的影响。请注意,PKNameConvention只适用于Organism而不适用于Animal。类似地,FKColumnNameConvention仅由Animal调用。因为Animal FK仅在内部用于挂接继承层次结构,所以该属性为null。因此,您将获得OrganismId作为FK名称。要设置此PK / FK,您需要使用IJoinedSubclassConvention。 (为了完整性,我已经包含了你的TableNameConvention和PrimaryKeyNameConvention。)
public class TableNameConvension : IClassConvention, IClassConventionAcceptance {
public void Apply(IClassInstance instance) {
instance.Table(instance.EntityType.Name + "Table");
}
public void Accept(IAcceptanceCriteria<IClassInspector> criteria) {
criteria.Expect(x => x.TableName, Is.Not.Set);
}
}
public class PrimaryKeyNameConvention : IIdConvention {
public void Apply(IIdentityInstance instance) {
instance.Column(instance.EntityType.Name + "Id");
}
}
public class JoinedSubclassIdConvention : IJoinedSubclassConvention
{
public void Apply(IJoinedSubclassInstance instance) {
instance.Table(instance.EntityType.Name + "Table");
instance.Key.Column(instance.EntityType.Name + "Id");
}
}
这会产生:
OrganismTable
OrganismId
AnimalTable
AnimalId
使用从AnimalTable.AnimalId到OrganismTable.OrganismId的FK。
请注意,由于查询实体时需要连接数,因此table-per-concrete-class不是继承映射的首选。通常,每个子类的表或每个类的表层次结构是更好的选择。我将把它作为练习让读者调查inheritance strategies上NHibernate文档的差异。