【问题标题】:Explicit value for identity column error on insert with nHibernate relationship使用 nHibernate 关系插入时标识列错误的显式值
【发布时间】:2014-12-11 17:58:04
【问题描述】:

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

我收到此错误:

无法为表中的标识列插入显式值 IDENTITY_INSERT 设置为 OFF 时的“Bookings_Locations”。

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

实体

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); 

我以前没有做过这样的关系,所以可能会很远......

任何帮助表示赞赏:)

编辑:

我现在有一个错误:

“对象引用未设置为对象的实例。”

...当SessionFactory.OpenSession 运行时。

这有点关系:

public class BookingLocation
{
        public BookingLocation(Booking inBooking)
        {
            this.Booking = inBooking;
            inBooking.AddBookingLocation(this);
        } 
}

...因为当我删除它运行的构造函数时(考虑不添加BookingLocation

我猜在它打开数据库时,根据您的示例,没有实例被传递到构造函数中。你懂我的意思吗?

【问题讨论】:

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


    【解决方案1】:

    我认为这不是 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 on 设置为 0。这可能会阻止 NHibernate 发送 ID 列值 0。这是假设您没有尝试在应用中生成应直接插入数据库的 ID。


    回复评论:

    如果 Booking 类需要 BookingLocation 的集合,则 BookingLocation 表需要像 BookingID 这样的 FK。 (又名,SELECT * from BookingLocation WHERE BookingID = 123,为您获取 Booking 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。

    这也意味着如果你保存了 Booking,你需要确保你已经加载了 BookingLocations,因为我认为如果没有加载它们,它会让你的 BookingLocation 表看起来像 BookingLocation 中的集合。 . 在这种情况下,由于它是空的,它将删除 BookingLocations。同样,您可能希望从 BookingLocation 的 Booking References 映射中删除 Cascade.All。即,如果您删除单个 BookingLocation,您不想删除与之关联的 Booking - 可能还有其他 BookingLocation。

    一般来说,我不在映射中使用 Cascade,而是将我的集合设置为 Inverse()。但是,通过使用反向集合映射,BookingLocations 不会在您保存预订时自动保存。您将不得不返回手动保存它们:

    using (var session = CreateNewSession())
    {
        using (var trans = session.BeginTransaction())
        {
            session.Save(myNewBooking)
            myNewBooking.BookingLocations.ForEach(x => session.Save(x));
            trans.Commit();
        }
    }
    

    总结:

    预订(表) ID Booking_Locations(表) ID 预订编号 预订(类) ID IList BookingLocation(类) ID 预订(实例)

    预订地图

    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
    

    【讨论】:

    • 嗨,乔,谢谢。我不明白以“此示例似乎...”开头的段落,但这可能是因为我试图从 Booking 中的 ID 列映射到 BookingLocation 中的 ID 列。事实并非如此,我在 Bookings 表上有一个名为 BookingLocationId 的外键。也许这就是我要出错的地方?
    • 哦。我认为您的模型有点混乱。您有一个 Booking,其中包含 BookingLocations 的集合。因此,您的 Booking 表不能简单地具有 BookingLocationID(即 1 比 1) - 您的 BookingLocation 需要具有 FK,BookingID。我正在编辑我的答案以显示一些代码。
    • 我重新措辞了那段。 SQL 错误可能是一个红鲱鱼。该模型看起来需要先修改才能正确调试。此外,如果您还没有它,请获取 NHibernate Profiler 的试用版,添加一个引用并在您的代码中对其进行初始化,然后再次尝试您的操作并查看正在执行的 SQL。这将有助于消除围绕 NH 试图做的事情的谜团,而不是通过摆弄映射选项的细微差别而在黑暗中刺伤。
    • 好的,我自己搞糊涂了。几天前我有这个,确实 BookingLocations 上已经存在 bookingId 列。问题是它在插入时保存了预订记录的 ID,而不是预订表(旧的设计不佳的数据库)上也存在的 BookingId 字段。无论如何,我想我需要在 BookingLocations 上创建一个新字段(作为外键服务器 - 正如你所说),而不是在 Bookings 上(我觉得我很困惑)。令人惊讶的是,nHibernate(和你)能够很好地理解我的废话;)感谢 nHibernate 分析器提示!
    • 你是传奇乔!非常感谢您的帮助!我现在要试一试...
    【解决方案2】:
    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();
    }
    

    【讨论】:

    • 是的,我也遇到这种情况,这不起作用。奇怪的是,因为这似乎是确切的问题,而在此之前我有 XML 映射,它做的事情完全相同(据我所知)没有得到这个错误
    【解决方案3】:

    为什么不将 Id 属性设为可空 int 类型?从技术上讲,你不会马上知道它的价值。

    【讨论】:

      【解决方案4】:

      我知道问题已得到解答,但我还是决定发布,因为我遇到了同样的问题,但解决方案不同。

      在我的例子中,nhibernate 也抱怨试图将值插入标识列 - 即使 id 从未设置,因此由于其数据类型(长)而导致“0”。

      解决方案非常简单... 我忘记将 SaveOrUpdate 包装在事务中 :-/ 我已经这样做了很多次,但猜想这发生在深夜会话

      希望对某人有所帮助。

      干杯...

      【讨论】:

        猜你喜欢
        • 2015-07-02
        • 2023-03-18
        • 1970-01-01
        • 2021-03-10
        • 2011-05-06
        • 2011-06-14
        • 2017-10-26
        • 2015-10-27
        • 2017-12-31
        相关资源
        最近更新 更多