我有2个NHibernate实体(表格),它们是一对多的关系。
我收到此错误:
无法在表中插入identity列的显式值 ' Bookings_Locations'当IDENTITY_INSERT设置为OFF时。
尝试保存(插入)新记录时。
实体
public class Booking
{
public virtual int Id { get; set; }
public virtual void AddBookingLocation(BookingLocation bookingLocationToAdd)
{
bookingLocationToAdd.Booking = this;
this.BookingLocations.Add(bookingLocationToAdd);
}
public virtual void RemoveBookingLocation(BookingLocation bookingLocationToRemove)
{
this.BookingLocations.Remove(bookingLocationToRemove);
}
public virtual IList<BookingLocation> BookingLocations { get; set; }
public Booking()
{
BookingLocations = new List<BookingLocation>();
}
}
public BookingMap()
{
Table("Bookings");
Id(x => x.Id).Column("ID");
HasMany(x => x.BookingLocations)
.KeyColumn("ID")
.Not.LazyLoad().Cascade.All();
}
public class BookingLocation
{
public virtual int Id { get; set; }
public virtual Booking Booking { get; set; }
}
public BookingLocationMap()
{
Table("Bookings_Locations");
Id(x => x.Id).Column("ID");
References(x => x.Booking)
.Column("ID")
.Not.LazyLoad().Nullable()
.Cascade.All();
}
BookingLocation
的主键(ID
)的值一旦初始化就为0,并且我没有为其分配任何内容。这让我相信问题在某种程度上是关系映射。
我在调用屏幕截图中的方法之前执行此操作:
Booking.AddBookingLocation(BookingLocation);
this.bookingRepo.insertBooking(Booking, BookingLocation);
我之前没有这样的关系,所以可能会离开......
任何帮助表示赞赏:)
修改
我现在有一个错误:
&#34;对象引用未设置为对象的实例。&#34;
......当SessionFactory.OpenSession
运行时。
它与某些事情有关:
public class BookingLocation
{
public BookingLocation(Booking inBooking)
{
this.Booking = inBooking;
inBooking.AddBookingLocation(this);
}
}
...因为当我删除它运行的构造函数时(想到没有添加BookingLocation
)
我想当它打开数据库的时候,根据你的例子,没有实例传递给构造函数。你懂我的意思吗?
答案 0 :(得分:2)
我认为这不是特定于NHibernate的错误,而是SqlServer - 特别是表模式。
据我了解,您没有在客户端上设置PK值,并且您希望在数据库中生成ID,对吗?
您获得的错误来自SqlServer,表明已为此配置了表,但您正在向数据库发送ID。
启用此功能似乎非常简单。
但也许这不是你想要做的。
此示例在插入具有Identity列的表时导致问题,当插入指定应插入的ID时,而不是让表生成它...即,table1开始将值递增为1,而table2从4开始。该示例将记录成功插入table1(此行将具有ID:1),然后尝试将同一行ID和所有行插入table2。通常,当插入带有Identity列的表时,您不会指定ID,因为该表将为您生成它。
除了Anton建议的GeneratedBy之外,也许尝试将映射中的DefaultValue设置为0。这可能会阻止NHibernate发送ID列值为0.这假设您没有尝试在应用程序中生成应直接插入数据库的ID。
如果Booking类需要BookingLocations的集合,则BookingLocation表需要FK,如BookingID。 (又名,SELECT *来自BookingLocation WHERE BookingID = 123,获取预订123的BookingLocations列表)
要映射此关系,您的BookingMap应如下所示(仅显示集合映射)
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.All表示您不应必须手动保留(session.Save)BookingLocation。
这也意味着如果您保存预订,您需要确保已加载BookingLocations,因为我认为如果没有加载它们,它将使您的BookingLocation表看起来像预订中的集合。在这种情况下,由于它是空的,它将删除BookingLocations。同样,您可能希望从BookingLocation中的Booking References映射中删除Cascade.All。即如果您删除单个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
答案 1 :(得分:1)
public BookingLocationMap()
{
Table("Bookings_Locations");
Id(x => x.Id).Column("ID").GeneratedBy.Identity(); // Try this
References(x => x.Booking)
.Column("ID")
.Not.LazyLoad().Nullable()
.Cascade.All();
}
答案 2 :(得分:0)
为什么不将类型为nullable的Id属性设为int?从技术上讲,你不会马上知道价值。
答案 3 :(得分:0)
我知道这个问题已得到解答,但我决定发帖,因为我遇到了同样的问题并采用了不同的解决方案。
就我而言,nhibernate还抱怨尝试将值插入到标识列中 - 即使id从未设置过,因此因为数据类型(长)而导致“0”。
解决方案非常简单...... 我忘了将SaveOrUpdate包装在一个交易中: - /我已经这么做了很多次但是猜测这种情况发生在深夜会议中 argh
希望能有所帮助。
干杯...