Подтвердить что ты не робот

Конфигурация NHibernate для однонаправленного отношения "один ко многим"

Я пытаюсь настроить отношения следующим образом. Каждый элемент Мастер имеет один или несколько элементов Подробно:

public class Detail {
    public virtual Guid DetailId { get; set; }
    public virtual string Name { get; set; }
}
public class Master {
    public virtual Guid MasterId { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Detail> Details { get; set; }
}

И отображения:

public class MasterMap : ClassMap<Master> 
{
    public MasterMap() 
    {
        Id(x => x.MasterId);
        Map(x => x.Name);
        HasMany(x => x.Details).Not.KeyNullable.Cascade.All();
    }
}
public class DetailMap : ClassMap<Detail> 
{
    public DetailMap() 
    {
        Id(x => x.Id);
        Map(x => x.Name);
    }
}

Таблица базы данных Мастер:

masterId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL

и Подробно:

DetailId   uniqueidentifier NOT NULL
name       nvarchar(max) NULL
MasterId   uniqueidentifier NULL
foreign key (masterId) references [Master]

Мне не нужно иметь ссылку из Detail back to Master - другими словами, объекты Detail сами по себе просто не интересны для моего домена. Они всегда будут доступны через свой объект "Мастер".

Используя такой код:

Master mast = new Master 
{
    MasterId = new Guid(),
    Name = "test",
    Details = new List<Detail> 
    {
        new Detail { .DetailId = new Guid(), .Name = "Test1" },
        new Detail { .DetailId = new Guid(), .Name = "Test1" }
    }
};

using (transaction == Session.BeginTransaction) 
{
    Session.Save(mast);
    transaction.Commit();
}

Это отлично работает, за исключением сумасшедшего ограничения, описанного в этом сообщении: NHibernate делает INSERT и сначала помещает Detail.MasterId как NULL, затем устанавливает UPDATE это к реальному MasterId.

На самом деле, я не хочу подробные записи с помощью NULL MasterIds, поэтому, если я установил для поля MasterId значение NOT NULL, INSERT to Detail завершится неудачно, потому что, как я сказал, NHibernate пытается ввести MasterId = NULL.

Я думаю, мой вопрос сводится к следующему:

Как я могу заставить приведенный выше пример кода работать с моей существующей моделью домена (например, без добавления свойства Detail.Master) и в поле Detail.MasterId в базе данных, установленной в NOT NULL?

Есть ли способ заставить Nhibernate просто поместить правильный MasterId в начальный INSERT, а не после запуска UPDATE? Есть ли смысл в этом дизайнерском решении? - Я изо всех сил пытаюсь понять, почему так будет сделано.

4b9b3361

Ответ 1

Вы не можете. Чтобы процитировать ссылку из моего ответа по другому вопросу, с которым вы связались:

Очень важно Примечание. Если столбец <key> ассоциации <one-to-many> объявлен NOT NULL, NHibernate может вызвать нарушения ограничений при создании или обновлении ассоциации. Чтобы предотвратить эту проблему, вы должны использовать двунаправленную связь со многими ценными концами (набором или сумкой), обозначенными как inverse="true". См. Обсуждение двунаправленных ассоциаций позже в этой главе.

Изменить:, как правильно указал Хаззик, это изменилось в NHibernate 3 и выше. Документы, к сожалению, не были обновлены, поэтому здесь Хаззик:

[Если вы установили inverse="false" и not-null на <key>, NH3 и выше будут выполнять только две вставки вставки вставки-вставки-обновления.

Ответ 2

NH3 и выше позволяют исправить сохраненные объекты в случае однонаправленного преобразования "один ко многим" без раздражающего цикла save null - save - update, если вы установите как not-null="true" on <key> и inverse="false" на < one-to-many >

Свободный фрагмент кода FluentNHibernate для этого:

public class MasterMap : ClassMap<Master> 
{
    public MasterMap() 
    {
        Id(x => x.MasterId);
        Map(x => x.Name);
        HasMany(x => x.Details)
            .Not.Inverse()     //these options are very
            .Not.KeyNullable() //important and work only if set together 
            .Not.KeyUpdate()   //to prevent double update
            .Cascade.All();
    }
}

Ответ 3

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