NHibernate - Вставить строку в таблицу с первичным ключом «автоинкремент» и столбцом со ссылкой NOT NULL на первичный ключ - PullRequest
0 голосов
/ 02 мая 2011

Модель БД:
- 1 стол "Программное обеспечение"
- Столбец "ID" (длинный) -> Первичный ключ с автоматическим приращением
- Столбец «Совместимость» (длинный) -> НЕ ПУСТО, FK в «ИД»
- колонка "Описание" (варчар)

 
CREATE TABLE `softwares` (
    `ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `CompatibilityID` BIGINT(20) NOT NULL,
    `Description` VARCHAR(50) NULL DEFAULT NULL,
    PRIMARY KEY (`ID`),
    INDEX `FK_Software_Compatibility` (`CompatibilityID`),
    CONSTRAINT `FK_Software_Compatibility` FOREIGN KEY (`CompatibilityID`) REFERENCES `softwares` (`ID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=0

Эта таблица пуста.
При включенных проверках ссылок новая строка не может быть вставлена, поскольку проверка ссылок для столбца "Совместимость" требует допустимого значения в столбце "ID".
Но значение «ID» будет известно только после того, как была произведена вставка!

Единственный способ найти новую строку - временно отключить проверку ссылок в собственном SQL.
Вставка-Пример:

 
START TRANSACTION;    
  SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;

  INSERT
    INTO
        softwares
        (Description)
    VALUES
        ('MySoftware');         


    UPDATE `softwares`
    SET
        `CompatibilityID`=LAST_INSERT_ID()
    WHERE `ID`=LAST_INSERT_ID();

  SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
COMMIT;



В нативном SQL это возможно, но я хочу сделать то же самое с NHibernate.

 
//class model
class Software
{
    public virtual long ID { get; set; }
    public virtual Software Compatibility { get; set; }
    public virtual string Description { get; set; }
}

//mapping with FluentNHibernate
class SoftwareMap : ClassMap
{
    public SoftwareMap()
    {
        Id(x => x.ID)
            .GeneratedBy.Native();

        References(x => x.Compatibility)
         .Column("CompatibilityID")
         .ForeignKey("FK_Software_Compatibility")
         .Not.Nullable();

        Map(x => x.Description);
    }
}


Код для вставки программных записей:

 
Software software1 = new Software();
software1.Description = "Test software 1";
software1.Compatibility = software1;

Software software2 = new Software();
software2.Description = "Test software 2";
software2.Compatibility = software1;


using (ITransaction transaction = Session.BeginTransaction()) { 
    //ISQLQuery queryChecksOff = Session.CreateSQLQuery("/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;");
    //int dummy = queryChecksOff.ExecuteUpdate();

    Session.Save(software1);
    Session.Save(software2);

    //ISQLQuery queryChecksOn = Session.CreateSQLQuery("/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;");
    //dummy = queryChecksOn.ExecuteUpdate();

    transaction.Commit();
}


NHibernate выдает ошибку при выполнении строки "Session.Save (software1);":
«свойство not-null ссылается на нулевое или временное значение Domain.Software.Compatibility»

Эта ошибка является правильной, поскольку указанное программное обеспечение «software1» еще не было сохранено в БД!

Я пытался отключить проверки целостности перед вставкой с помощью «CreateSQLQuery ()» в приведенном выше коде, но безуспешно.
Это также имеет смысл, поскольку NHibernate не отправлял SQL-операторы в БД из-за неправильной целостности.

Теперь, что я могу сделать?
1) Могу ли я отключить проверку целостности NHibernate? (Было бы плохое кодирование ...)
2) Могу ли я сказать NHibernate, что эта ссылка в порядке или обрабатывается по-другому?
3) Модель БД неверна?

...