Fluent NHibernate - как создать сопоставление таблиц на подклассы с помощью дискриминатора?

Я просмотрел много вопросов по SO и google относительно сопоставлений подклассов в nhibernate / fluent-nhibernate, и мне не удалось найти никого с той же проблемой, что и я. Я выполнил основные инструкции из вики-страницы fluent-nhibernate (http://wiki.fluentnhibernate.org/Fluent_mapping#Subclasses), но это не помогло.

У меня есть базовая сущность под названием Operation, с которой связана базовая таблица, затем у меня есть подтаблицы UnpaidCheque, Refund и т. Д. - первичный ключ для каждой из этих подтаблиц является внешним ключом, OperationId (PK) из Операционный стол.

Когда я создаю спецификацию постоянства и пытаюсь проверить свои сопоставления, он пытается сохранить все столбцы в таблице операций, а не сохранять в таблице операций, а затем сохранять определенные столбцы неоплаченного чека в таблице UnpaidCheque.

Ошибка:

could not insert: [UnpaidCheque][SQL: INSERT INTO Account.Operation (PaymentId, Amount, UnpaidOn, UnpaidByUserId, OperationType) VALUES (?, ?, ?, ?, 'U'); select SCOPE_IDENTITY()]
  ----> System.Data.SqlClient.SqlException : Invalid column name 'UnpaidOn'.
Invalid column name 'UnpaidByUserId'.

Как видите, он пытается сохранить значения в столбцах UnpaidByUserId и UnpaidOn, которые являются членами подтаблицы / класса, а не базы.

С другой стороны, тот факт, что он пытается вставить 'U' в столбец типа операции, указывает мне, что он, похоже, устанавливает правильное значение дескриминатора для типа класса. Единственное место, где я указал тип операции, - это вызов DiscriminatorValue () в карте классов, я не устанавливаю его явно где-либо еще.

Иерархия классов следующая:

public class Operation
    {
        public virtual long OperationId { get; set; }
        public virtual string OperationType { get; set; }
        public virtual long? PaymentId { get; set; }
        public virtual decimal Amount { get; set; }
    }

public class UnpaidCheque : Operation
    {
        public virtual DateTime UnpaidOn { get; set; }
        public virtual long UnpaidByUserId { get; set; }
    }

Отображения классов:

public class OperationMap : ClassMap<Operation>
    {
        public OperationMap()
        {
            Schema("Account");
            Table("Operation");
            LazyLoad();
            Id(_ => _.OperationId).Column("OperationId").GeneratedBy.Identity();
            Map(_ => _.PaymentId).Column("PaymentId").Nullable();
            Map(_ => _.Amount).Column("Amount").Not.Nullable();

            DiscriminateSubClassesOnColumn("OperationType");
        }
    }
public class UnpaidChequeMap : SubclassMap<UnpaidCheque>
{
    public UnpaidChequeMap()
        {
            Schema("Account");
            Table("UnpaidCheque");
            LazyLoad();
            DiscriminatorValue("U");
            KeyColumn("OperationId");
            Map(_ => _.UnpaidOn).Column("UnpaidOn").Not.Nullable();
            Map(_ => _.UnpaidByUserId).Column("UnpaidByUserId").Not.Nullable();
        }
}

Я не вижу ничего, что я сделал иначе, чем в примере, кроме добавления KeyColumn () в карту подклассов, однако я получаю то же сообщение об ошибке и без этого. Может ли кто-нибудь пролить свет на то, что я упустил, или на то, что я пытаюсь достичь, поддерживается nhibernate? Насколько я могу судить, так и должно быть.

Заранее спасибо!


person John Pappin    schedule 27.03.2012    source источник
comment
Кстати, ваша явная настройка столбцов избыточна, нет? Вы можете просто Map (_ = ›_.PaymentId) .Nullable () - без указания столбца (PaymentId), и он будет работать точно так же?   -  person PandaWood    schedule 10.02.2014
comment
@PandaWood - да, это правильно, это просто личное предпочтение, что я отображаю столбцы явно, но fluent будет предполагать, что свойство и столбец названы одинаково, если вы не указали его явно.   -  person John Pappin    schedule 10.11.2014


Ответы (2)


Чтобы использовать table-per-subclass С дискриминатором, работает следующее:

public class UnpaidChequeMap : SubclassMap<UnpaidCheque>
{
    public UnpaidChequeMap()
    {
        Schema("Account");
        DiscriminatorValue("U");
        Join("UnpaidCheque", j =>
        {
            j.KeyColumn("OperationId");
            j.Map(_ => _.UnpaidOn).Column("UnpaidOn").Not.Nullable();
            j.Map(_ => _.UnpaidByUserId).Column("UnpaidByUserId").Not.Nullable();
        }
    }
}
person AlexDev    schedule 27.01.2017
comment
Спасибо, @AlexDev. Наконец-то я получил дискриминатор и таблицу для каждого подкласса, чтобы работать !!! Думаю, никогда не поздно;) - person bounav; 04.12.2018

Мы нашли решение:

Дескриминаторы предназначены только для отображений, в которых все подклассы хранятся в одной таблице в базе данных.

Удаление строк:

DiscriminateSubClassesOnColumn("OperationType");

из родительского отображения и

DiscriminatorValue("U");

из дочернего сопоставления, и последующее удаление столбца из базы данных решило проблему.

person John Pappin    schedule 27.03.2012
comment
Как насчет раздела 8.1.3 документации nhibernate? Он предполагает, что таблица на подкласс отображение наследования с дискриминатором может использоваться. Однако я никогда не мог понять, как это сделать с беглым nhibernate. - person bounav; 11.05.2016
comment
@bounav Если вам все еще интересно, посмотрите мой ответ. - person AlexDev; 27.01.2017