Приводят ли однонаправленные ассоциации к необязательным полям внешнего ключа через NHibernate - PullRequest
2 голосов
/ 15 сентября 2009

Обновление Добавлены сопоставления ниже

Краткое изложение вопроса У меня есть база данных со многими обязательными полями внешнего ключа и база кода со многими однонаправленными ассоциациями. Я хочу использовать NHibernate, но, насколько я могу судить, я должен либо сделать поля внешнего ключа в базе данных NULLable (нереалистичный вариант), либо изменить ассоциации на двунаправленные (тоже не идеальные). Любые другие варианты, которые я пропустил?

Фон Я присоединился к проекту, который использует NHibernate для отображения таблиц 1: 1 на так называемые «технические» объекты. После извлечения данных объекты сопоставляются с фактической моделью предметной области (стиль AutoMapper, реализованный по-другому). Я знаю, что это ненужный шаг, и я хочу предложить удалить его команде. Однако я столкнулся с проблемой.

Модель предметной области содержит множество однонаправленных ассоциаций: у объекта Case есть список лиц, связанных с делом, но у людей нет ссылки на объект Case. В базовой схеме базы данных таблица Person имеет обязательное поле внешнего ключа, которое ссылается на идентификатор дела. Модель данных:

[ERD]
               PERSON
CASE           Id*            Ids are generated by the DB
Id*    <--FK-- CaseId*        * denotes required fields
(other)        (other)         

Модель предметной области выглядит следующим образом:

public class Person : DomainEntity
{ // DomainEntity implements Id. Non-essential members left out }

public class Case : DomainEntity
{
  public virtual IList<Person> Persons { get; set; }
}

Вызов session.Save () для Case приводит к ошибке базы данных (CaseId требуется при вставке в Person), потому что NHibernate начинается со вставки записей Person, затем следует запись Case и заканчивается обновлением столбца CaseId в Person записей. Если столбец CaseId в базе данных изменен на необязательный (разрешить NULL), все работает должным образом ... однако, в данный момент это изменение не вариант (модель базы данных используется несколькими приложениями, по крайней мере, для другого). год). Я нашел единственный способ заставить NHibernate правильно выполнять действия с базой данных, изменив связь на двунаправленную, то есть изменив Person на

public class Person : DomainEntity
{ 
  public virtual Case Case { get; set; }
}

Однако это повлечет за собой значительные изменения в существующей кодовой базе, поэтому я бы предпочел альтернативы, если они существуют. Я играл с сопоставлениями компонентов, но это плохо подходит, поскольку большинство ассоциаций в нашей модели не являются реальными (UML) композициями. Есть ли другие варианты, которые я пропустил? ТИА!

EDIT (Свободное) отображение для Case выглядит следующим образом:

public class CaseMapping : ClassMap<Case>
{
    public CaseMapping()
    {
        Not.LazyLoad();

        Id(c => c.Id).GeneratedBy.Identity();
        Map(x => x.Code).Not.Nullable().Length(20);
        Map(x => x.Name).Not.Nullable().Length(100);
        HasMany<Person>(x => x.Persons)
            .AsBag()
            .KeyColumn("CaseId")
            .ForeignKeyConstraintName("FK_Person_Case")
            .Cascade.AllDeleteOrphan();
    }
}

Если я использую SessionSource.BuildSchema для тестовой базы данных, это создает таблицу Person с обнуляемым столбцом CaseId. Я не нашел способа для этого работать с ненулевым полем CaseId без двунаправленных ассоциаций. Выполненные (псевдо) операторы SQL:

  1. INSERT INTO Case ...
  2. выберите @@ идентичность
  3. INSERT INTO Person / * (все столбцы, кроме CaseId) * /
  4. выберите @@ идентичность
  5. ОБНОВЛЕНИЕ Person SET CaseId =? ГДЕ Id =?; @ P0 = 2, @ p1 = 1

1 Ответ

1 голос
/ 17 сентября 2009

Я думаю, вам здесь не повезло. Документы в http://nhibernate.info/doc/nh/en/index.html#collections-onetomany состоянии:

Если столбец ассоциации объявлен NOT NULL, NHibernate может вызвать нарушения ограничений при создании или обновлении ассоциации. Чтобы предотвратить эту проблему, вы должны использовать двунаправленную ассоциацию с многозначным концом (набором или сумкой), помеченным как обратный = "true"

...