带有nHibernate关系的insert上的标识列错误的显式值

时间:2012-03-28 09:19:54

标签: nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

我有2个NHibernate实体(表格),它们是一对多的关系。

我收到此错误:

  

无法在表中插入identity列的显式值   ' Bookings_Locations'当IDENTITY_INSERT设置为OFF时。

尝试保存(插入)新记录时。

The error (easier to see if you open image in new tab)

实体

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

我想当它打开数据库的时候,根据你的例子,没有实例传递给构造函数。你懂我的意思吗?

4 个答案:

答案 0 :(得分:2)


我认为这不是特定于NHibernate的错误,而是SqlServer - 特别是表模式。

据我了解,您没有在客户端上设置PK值,并且您希望在数据库中生成ID,对吗?

您获得的错误来自SqlServer,表明已为此配置了表,但您正在向数据库发送ID。

启用此功能似乎非常简单。

http://sqlserverplanet.com/sql-server/cannot-insert-explicit-value-for-identity-column-in-table-table-when-identity_insert-is-set-to-off

但也许这不是你想要做的。

此示例在插入具有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

希望能有所帮助。

干杯...