流畅的NHibernate:自定义ForeignKeyConvention不使用显式指定的表名

时间:2012-02-13 18:13:57

标签: nhibernate fluent-nhibernate fluent-nhibernate-mapping

编辑:对于tl; dr crowd,我的问题是:如何从ForeignKeyConvention内部访问映射以确定给定类型映射到的表名?

长版:

我正在使用Fluent NHibernate来配置NHibernate,并且我有一个自定义外键约定,当我使用别名表和列时失败。

我的表使用一种约定,其中主键始终称为“PK”,外键是“FK”,后跟外键表的名称,例如“FKParent”。例如:

CREATE TABLE OrderHeader (
    PK INT IDENTITY(1,1) NOT NULL,
    ... 
)

CREATE TABLE OrderDetail (
    PK INT IDENTITY(1,1) NOT NULL, 
    FKOrderHeader INT NOT NULL,
    ...
)

为了完成这项工作,我构建了一个自定义的ForeignKeyConvention,如下所示:

public class AmberForeignKeyConvention : ForeignKeyConvention
{
    protected override string GetKeyName( Member member, Type type )
    {
        if ( member == null )
            return "FK" + type.Name;  // many-to-many, one-to-many, join

        return "FK" + member.Name; // many-to-one
    }
}

只要我的实体名称与表格相同,这就有效。但是当它们没有时就会中断。例如,如果我想将OrderDetail表映射到名为Detail的类,我可以这样做:

public class DetailMap : ClassMap<Detail>
{
    public DetailMap()
    {
        Table( "OrderDetail" );
        Id( o => o.PK );
        References( o => o.Order, "FKOrderHeader" );
        ...
    }
}

映射适用于加载单个实体,但是当我尝试使用连接运行任何类型的复杂查询时,它都会失败,因为AmberForeignKeyConvention类对列的映射方式做出了错误的假设。即,它假定外键应为“FK”+ type.Name,在本例中为Order,因此它调用外键“FKOrder”而不是“FKOrderHeader”。

正如我上面所说:我的问题是,我如何从ForeignKeyConvention内部访问映射,以确定给定类型的映射表名称(就此而言,它们的映射列名称也是如此)? this question的答案似乎暗示了正确的方向,但我不明白所涉及的课程是如何协同工作的。当我查看文档时,对于我查找的类(例如IdMapping class)来说,它是非常稀疏的。(

1 个答案:

答案 0 :(得分:1)

想法是加载映射

public class AmberForeignKeyConvention : ForeignKeyConvention
{
    private static IDictionary<Type, string> tablenames;

    static AmberForeignKeyConvention()
    {
        tablenames = Assembly.GetExecutingAssembly().GetTypes()
            .Where(t => typeof(IMappingProvider).IsAssignableFrom(t))
            .ToDictionary(
                t => t.BaseType.GetGenericArguments()[0], 
                t => ((IMappingProvider)Activator.CreateInstance(t)).GetClassMapping().TableName);
    }

    protected override string GetKeyName( Member member, Type type )
    {
        return "FK" + tablenames[type]; // many-to-one
    }
}