Я думаю, что это не ошибка NHibernate, а SqlServer, в частности схема таблицы.
Насколько я понимаю, вы не устанавливаете значения PK на клиенте и ожидаете, что идентификатор будет сгенерирован в базе данных, верно?
Ошибка, которую вы получаете от SqlServer, указывает, что таблица настроена для этого, но вы отправляете идентификатор в базу данных.
Включение этого кажется довольно тривиальным.
http://sqlserverplanet.com/sql-server/cannot-insert-explicit-value-for-identity-column-in-table-table-when-identity_insert-is-set-to-off
Но, возможно, это не то, что вы хотите сделать.
В этом примере возникает проблема при вставке в таблицу со столбцом Identity, когда вставка указывает идентификатор, который должен быть вставлен, а не позволяет таблице сгенерировать его. Т.е. table1 начинает увеличивать значения с 1, в то время как table2 начинается с 4. В этом примере запись успешно вставляется в table1 (эта строка будет иметь ID: 1), затем пытается вставить эту же строку, ID и все, в table2. Обычно при вставке в таблицу со столбцом Identity идентификатор не указывается, так как таблица сгенерирует его для вас.
Возможно, попробуйте установить значение DefaultValue в отображении на 0 в дополнение к GeneratedBy, предложенному Антоном. Это может помешать NHibernate отправлять значение столбца ID, равное 0. Это предполагает, что вы не пытаетесь генерировать идентификаторы в приложении, которые должны быть непосредственно вставлены в БД.
ответ на комментарий:
Если классу Booking требуется набор BookingLocations, таблице BookingLocation нужен FK, такой как BookingID. (иначе, ВЫБРАТЬ * из BookingLocation, ГДЕ BookingID = 123, возвращает вам список BookingLocations для бронирования 123)
Чтобы отобразить эту взаимосвязь, ваша карта бронирования должна выглядеть следующим образом (просто отображается сопоставление коллекции)
HasMany(x => x.BookingLocations)
.KeyColumn("BookingID") // aka, column in BookingLocation that links a row to this Booking
.Not.LazyLoad()
//.Cascade.All() // would advise against this until you can get it working explicitly
.Inverse() // use this instead
;
попробуйте изменить свое отображение ссылок следующим образом:
References(x => x.Booking)
.Column("BookingID") // the column in the locations table that points to the booking.
.Not.LazyLoad()
;
Пометка этой коллекции как Cascade. Все означает, что вы не должны вручную сохранять (сессия. Сохранять) расположение резервирования.
И это также означает, что если вы когда-либо сохраняете Booking, вам необходимо убедиться, что вы загрузили BookingLocations, потому что я думаю, что без их загрузки ваша таблица BookingLocation будет выглядеть как коллекция внутри Booking. В этом случае, поскольку он пуст, он удалит BookingLocations. Точно так же вы, вероятно, захотите удалить Cascade.All из сопоставления ссылок бронирования в BookingLocation Т.е., если вы удаляете одно BookingLocation, вы не хотите удалять бронирование, связанное с ним - могут быть другие BookingLocations.
Как правило, я не использую Cascade в своих отображениях, а вместо этого устанавливаю свои коллекции как Inverse () . Однако при использовании обратного сопоставления коллекции BookingLocations не будет автоматически сохраняться при сохранении бронирования. Вам придется вернуться к их сохранению вручную:
using (var session = CreateNewSession())
{
using (var trans = session.BeginTransaction())
{
session.Save(myNewBooking)
myNewBooking.BookingLocations.ForEach(x => session.Save(x));
trans.Commit();
}
}
В итоге:
Bookings (table)
ID
Booking_Locations (table)
ID
BookingID
Booking (class)
ID
IList<BookingLocation>
BookingLocation (class)
ID
Booking (instance)
BookingMap
base.HasMany<BookingLocation>(x => x.BookingLocations)
.KeyColumn("BookingID")
.Inverse()
.Not.LazyLoad()
;
BookingLocationMap
base.References<Booking>(x => x.Booking)
.Column("BookingID")
.Not.Nullable()
;
сохранение
var newBooking = new Booking(); // new booking
var newBLocation = new BookingLocation(); // new booking location
newBLocation.Booking = newBooking; // set booking instance on booking location
newBooking.BookingLocations.Add(newBLocation); // add new booking location to booking
session.Save(newBooking); // get the newBooking's ID from the DB insert
session.Save(newBLocation); // save the new location. NHibernate will set the FK col BookingID to the ID of the newly-persisted newBooking, and also get the new ID for newBLocation