Неполадки отображения Nhibernate с ошибкой вставки дочернего объекта
Я весь день бьюсь головой об стол со следующей проблемой Nhibernate.
Каждый банковский счет имеет один (и только один) набор ставок, связанных с ним. Первичный ключ таблицы банковских счетов BankAccountID также является внешним ключом и первичным ключом в таблице AccountRate.
public class BankAccount
{
public virtual int BankAccountId { get; set; }
public virtual string AccountName { get; set;}
public virtual AccountRate AccountRate {get;set;}
}
public class AccountRate
{
public virtual int BankAccountId { get; set; }
public virtual decimal Rate1 { get; set; }
public virtual decimal Rate2 { get; set; }
}
У меня есть следующие сопоставления HBM для BankAccount:
<class name="BankAccount" table="BankAccount">
<id name ="BankAccountId" column="BankAccountId">
<generator class="foreign">
<param name="property">
AccountRate
</param>
</generator>
</id>
<property name ="AccountName" column="AccountName" />
<one-to-one name="AccountRate" class="AccountRate" constrained="true" cascade="save-update"/>
</class>
и следующее для AccountRate:
<class name="AccountRate" table="AccountRate">
<id name ="BankAccountId" column="BankAccountId">
<generator class="native" />
</id>
<property name ="Rate1" column="Rate1" />
<property name ="Rate2" column="Rate2" />
</class>
Существующий объект BankAccount можно без проблем прочитать из базы данных. Однако при создании нового BankAccount оператор вставки завершается неудачно;
Cannot insert the value NULL into column 'BankAccountId'
Проблема заключается в том, что дочерний объект AccountRate создается первым. Поскольку он еще не получил идентификатор от своего родителя, вставка завершается неудачно.
Я думаю, что я правильно сказал, что если бы свойство AccountRate на BankAccount было коллекцией, я мог бы использовать следующее?
Inverse=True
чтобы заставить родителя быть вставленным первым.
Кто-нибудь может мне с этим помочь? Я действительно не хочу использовать коллекцию, между этими таблицами существует только однонаправленное отношение один-к-одному.
Спасибо
Павел
2 ответа
Хорошо, я думаю, что я исправил проблему. Похоже, что моя проблема - это классическая однозначная связь с общими значениями первичного ключа. Ответ был найден в результате хорошего ночного сна, а затем на странице 192-193 "Nhibernate в действии".
Сначала был ряд ошибок, которые нуждались в исправлении. Это потребовало модификации как классов, так и файлов HBM.
Во-первых, каждый класс должен содержать свойство другого класса, поэтому мне нужно было добавить свойство BankAccount в класс AccountRate.
public class BankAccount
{
public virtual int BankAccountId { get; set; }
public virtual string AccountName { get; set;}
public virtual AccountRate AccountRate {get;set;}
}
public class AccountRate
{
public virtual int BankAccountId { get; set; }
public virtual decimal Rate1 { get; set; }
public virtual decimal Rate2 { get; set; }
Public virtual BankAccount BankAccount {get;set;}
}
Я также сделал ошибку в файле BankAccount HBM, я не должен был делать класс генератора чужим. Это должно было быть в классе AccountRate. Ограничение также необходимо было удалить из связи один-к-одному. Новый файл BankAccount HBM выглядит следующим образом.
<class name="BankAccount" table="BankAccount">
<id name ="BankAccountId" column="BankAccountId">
<generator class="native">
</id>
<property name ="AccountName" column="AccountName" />
<one-to-one name="AccountRate" class="AccountRate" cascade="all"/>
</class>
Затем для AccountRate HBM необходим класс генератора, установленный на чужой, и добавлен тег "один к одному", чтобы завершить отношения между классами.
<class name="AccountRate" table="AccountRate">
<id name ="BankAccountId" column="BankAccountId">
<generator class="foreign">
<param name="property">BankAccount</param>
</generator>
</id>
<property name ="Rate1" column="Rate1" />
<property name ="Rate2" column="Rate2" />
<one-to-one name="BankAccount" class="BankAccount" constrained="true" />
</class>
Спасибо всем, кто нашел время, чтобы взглянуть на эту проблему. Я думаю, это все часть кривой.
Павел
Один быстрый способ обойти это - сделать BankAccountId обнуляемым. NHibernate должен вставить запись в таблицу BankAccount с нулевым идентификатором, а затем обновить идентификатор.
В прошлом я наткнулся на способ заставить его делать начальную вставку с правильным идентификатором вместо нуля. К сожалению, я не могу на всю жизнь вспомнить, что я изменил.