NHibernate: проблема при попытке сохранить объект, содержащий коллекции - PullRequest
1 голос
/ 23 сентября 2011

Мне нужна помощь.

Я только начинаю с NHibernate и использую Fluent для сопоставлений. Казалось, все работает нормально до сегодняшнего дня. Вот история:

У меня есть две таблицы в моей базе данных: Store и WorkDay Первая таблица содержит информацию о магазине, а таблица WorkDay содержит информацию о днях недели и времени начала / окончания, когда магазин открыт. Store содержит столбец Guid StoreID PK, на который есть ссылка в таблице WorkDay . Итак, у меня есть файл сопоставления для Store , где у меня есть HasMany ассоциация с таблицей WorkDay и соответствующий POCO для Store . Теперь, когда я заполняю все необходимые данные и пытаюсь сохранить их в базе данных, я получаю исключение, сообщающее, что вставка в таблицу WorkDay завершилась неудачно, поскольку StoreID имеет нулевое значение и ограничение таблицы не допускает пустые значения для этого столбца (что, конечно, является ожидаемым поведением).

Я понимаю причину этого исключения, но я не знаю, как его решить. Причина сбоя вставки заключается в том, что StoreID генерируется при вставке, но коллекция [b] WorkDay [/ b] сначала сохраняется , во время, когда StoreID еще не создан!

Итак, как заставить NHibernate сгенерировать этот идентификатор для передачи его в зависимые таблицы? Или есть другое решение для этого?

Спасибо!

Вот код для StoreMap

public class StoreMap : ClassMap<Store> {
    public StoreMap() {
        Id(x => x.StoreID)
            .GeneratedBy.GuidComb();
        Map(x => x.City);
        Map(x => x.Description);
        Map(x => x.Email);
        Map(x => x.Fax);
        Map(x => x.ImageData).CustomType("BinaryBlob");
        Map(x => x.ImageMimeType);
        Map(x => x.Name);
        Map(x => x.Phone);
        Map(x => x.Street);
        Map(x => x.Zip);

        HasMany(x => x.WorkDays)
            .Inverse().KeyColumn("StoreID").ForeignKeyCascadeOnDelete()
            .Cascade.All();
    }
}

и это для WorkDayMap

public class WorkDayMap : ClassMap<WorkDay>{
    public WorkDayMap() {
        Id(x => x.WorkDayID)
            .GeneratedBy.Identity();
        Map(x => x.TimeOpen);
        Map(x => x.TimeClose);
        References(x => x.Store).Column("StoreID");
        References(x => x.Day).Column("DayID");
    }
}

Ответы [ 2 ]

0 голосов
/ 23 сентября 2011

Вероятно, он вставляет рабочий день перед магазином, потому что первый имеет генератор identity.Это заставляет NH выполнить инструкцию INSERT для генерации идентификатора.guid.comb генерируется в памяти, NH не нуждается в базе данных.

NH пытается получить доступ к БД в самый последний возможный момент времени, чтобы избежать ненужных обновлений и использовать пакеты.Рабочий день вставляется, когда вы вызываете session.Save, Store вставляется, когда он сбрасывает сеанс в следующий раз (например, при коммите).

Вы не должны использовать генератор идентификаторов (если вы не обязаны его использовать),В любом случае, это плохо сказывается на производительности.


Если это все еще не работает, вам, вероятно, нужно удалить ограничение not-null для внешнего ключа.NH не может решить это каждый раз.Существует некоторый умный алгоритм, который также способен справляться с рекурсивными ссылками.Но иногда бывают случаи, когда он устанавливает внешний ключ на ноль и обновляет его позже, даже если будет решение, позволяющее избежать этого.

0 голосов
/ 23 сентября 2011

NHibernate не должен сначала вставлять WorkDay, поэтому в вашем коде должна быть ошибка. Убедитесь, что вы делаете все следующее:

  1. Добавить все WorkDay объекты в коллекцию WorkDays.
  2. Установить свойство Store для всех объектов WorkDay для родительского объекта.
  3. Вызовите session.Save() для Store, но не для WorkDay объектов.

edit: Вы также должны заметить, что ForeignKeyCascadeOnDelete() ничего не изменит во время выполнения. Это просто атрибут для инструмента hbm2ddl. Если вы хотите, чтобы NHibernate удалял удаленные записи, используйте Cascade.AllDeleteOrphan().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...