Свободный NHibernate: Custom ForeignKeyConvention не работает с явно указанными именами таблиц

РЕДАКТИРОВАТЬ: для толпы tl; dr мой вопрос: как мне получить доступ к сопоставлениям изнутри 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, чтобы определить имя сопоставленной таблицы данного типа (и в этом отношении имена сопоставленных столбцов тоже)? Ответ на этот вопрос, кажется, намекает в правильном направлении, но я не понимаю, как задействованные классы работают вместе. Когда я просматриваю документацию, она ужасно скудна для классов, которые я искал (например, класс IdMapping).


person Katie Kilian    schedule 13.02.2012    source источник


Ответы (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
    }
}
person Firo    schedule 14.02.2012
comment
Блестяще. Оно работало завораживающе. Мне пришлось поменять .AsDictionary на .ToDictionary, но в остальном все было идеально. Большое спасибо! - person Katie Kilian; 16.02.2012
comment
Примечание для всех, кто использует этот код: у меня также была ситуация, когда имена моих таблиц получали обратную кавычку. Мне пришлось отфильтровать строку, чтобы удалить обратные кавычки, например: return "FK" + tablenames[type].Replace( "`", "" ); - person Katie Kilian; 19.02.2012