流畅的NHibernate自动化:如何自定义子类表名和键列名?

时间:2011-03-28 00:48:01

标签: nhibernate fluent-nhibernate

我认为这之前一定是问过,但是我用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);
    }
}

有什么想法吗?感谢。

1 个答案:

答案 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文档的差异。