簡體   English   中英

不會插入流利的NHibernate多對多列

[英]Fluent NHibernate Many to Many with extra column does not insert

我正在使用Fluent Nhibernate的多對多映射和額外的列來解決Fluent Nhibernate問題

我已經復制了映射並編寫了我能做的最小程序...但是它不會保存...任何人都能夠提供一些見識嗎?

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Inventory> Inventory { get; set; }

    public Product()
    {
        Inventory = new List<Inventory>();
    }
}

public class Warehouse
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Inventory> Inventory { get; set; }

    public Warehouse()
    {
        Inventory = new List<Inventory>();
    }
}

public class Inventory
{
    public Product Product { get; set; }
    public Warehouse Warehouse { get; set; }
    public bool StockInHand { get; set; }


    // override object.Equals
    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        var i = obj as Inventory;

        return ((i.Product.Id == this.Product.Id) 
             && (i.Warehouse.Id == this.Warehouse.Id));
    }

    // override object.GetHashCode
    public override int GetHashCode()
    {
        return 9999;
    }
}
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Not.LazyLoad();
        Table("Product");
        Id(x => x.Id).GeneratedBy.Assigned();
        Map(x => x.Name);
        HasMany(x => x.Inventory).AsBag()
         .Cascade.All()
         //.Inverse()
         .Table("Inventory");
    }
}
public class WarehouseMap : ClassMap<Warehouse>
{
    public WarehouseMap()
    {
        Not.LazyLoad();
        Table("Warehouse");
        Id(x => x.Id).GeneratedBy.Assigned();
        Map(x => x.Name);
        HasMany(x => x.Inventory).AsBag()
         .Cascade.All()
         .Inverse()
         .Table("Inventory");
    }
}
public class InventoryMap : ClassMap<Inventory>
{
    public InventoryMap()
    {
        Not.LazyLoad();
        Table("Inventory");
        CompositeId()
          .KeyReference(x => x.Product, "Product_id")
          .KeyReference(x => x.Warehouse, "Warehouse_id");

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

和程序...

using (var session = sessionFactory.OpenSession())
{
    using (var transaction = session.BeginTransaction())
    {
        Product p = new Product() { Id = 1, Name="product" };
        Inventory i = new Inventory() { StockInHand = true };
        i.Product = p;
        p.Inventory.Add(i);
        Warehouse w = new Warehouse() { Id = 1, Name = "warehouse" };
        i.Warehouse = w;
        w.Inventory.Add(i);

        session.SaveOrUpdate(p);

        session.Flush();

        transaction.Commit();
    }
}

我得到的例外是

constraint failed\r\nforeign key constraint failed

我還輸出了對我來說看起來正確的create語句。

create table Inventory (
    Product_id INT not null,
   Warehouse_id INT not null,
   StockInHand BOOL,
   primary key (Product_id, Warehouse_id),
   constraint FK2B4C61665C5B845 foreign key (Product_id) references Product,
   constraint FK2B4C616A6DE7382 foreign key (Warehouse_id) references Warehouse)

create table Product (
    Id INT not null,
   Name TEXT,
   primary key (Id)
)

create table Warehouse (
    Id INT not null,
   Name TEXT,
   primary key (Id)
)

以及在異常之前運行的SQL。

NHibernate:
INSERT
INTO
    Warehouse
    (Name, Id)
VALUES
    (@p0, @p1);
@p0 = 'warehouse' [Type: String (0)], @p1 = 1 [Type: Int32 (0)]
NHibernate:
INSERT
INTO
    Inventory
    (StockInHand, Product_id, Warehouse_id)
VALUES
    (@p0, @p1, @p2);
@p0 = True [Type: Boolean (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 1 [Type: Int32 (0)]

那么,這應該如何正常工作?!

您出現問題的原因是NHibernate嘗試在“ Warehouse記錄之前插入“ Inventory ”記錄。 這是因為插入的順序受session.Save調用的順序控制。 根據此信息,我嘗試了多種代碼變體,以防止出現外鍵約束錯誤。 我在下面發布了我最好的解決方案。

using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
    var warehouse = new Warehouse() { Id = 1, Name = "warehouse" };
    session.Save(warehouse);

    var product = new Product() {Id = 1, Name = "product"};
    var inventory = new Inventory 
                     { StockInHand = true, Product = product, Warehouse = warehouse};

    product.Inventory.Add(inventory);
    warehouse.Inventory.Add(inventory);

    session.Save(product);

    transaction.Commit();
}

我發現的一件事使我感到非常驚訝,如果您將session.Save(warehouse)放置在Warehouse warehouse.Inventory.Add(inventory)之后,那么NHibernate不會首先插入Warehouse記錄,並且會引發外鍵錯誤。

最后,要獲取下面列出的三個插入語句,必須在ProductMap映射類中恢復Inverse() 否則,NHibernate將發出其他更新語句。

INSERT INTO Warehouse (Name, Id) VALUES (@p0, @p1);@p0 = 'warehouse' 
[Type: String (4000)], @p1 = 1 [Type: Int32 (0)]

INSERT INTO Product (Name, Id) VALUES (@p0, @p1);
@p0 = 'product' [Type: String (4000)], @p1 = 1 [Type: Int32 (0)]

INSERT INTO Inventory (StockInHand, Product_id, Warehouse_id) VALUES (@p0, @p1, @p2);
@p0 = True [Type: Boolean (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 1 [Type: Int32 (0)]

對於任何可能跟隨我的腳步的人...

我的問題是我想在鏈接表中存儲一些有關實體之間關系的信息。 通常,數據庫術語中的多對多關系在域對象之間具有鏈接表。

使用問題中概述的結構,需要先插入倉庫和產品,然后才能插入庫存物料。 必須最后插入一個清單物料,以便在保存之前兩個外鍵約束都已就位。

Insert into Product

Insert into Warehouse

Insert into Inventory (Note this happens **after** the primary keys are 
inserted in Warehouse and Product!)

但是,我使用我的映射Fluent NHibernate生成以下內容...

Insert into Product

Insert into Inventory (Foreign Key constraint violated, no Warehouse)

..一定是不正確的,因為倉庫上沒有主鍵! 我了解問題,但不了解解決方案...我設法產生了以下兩種解決方案,但我認為這兩種方法都不理想。

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Not.LazyLoad();
        Table("Product");
        Id(x => x.Id, "Product_id").GeneratedBy.Assigned();
        Map(x => x.Name).Column("Name").Length(10);
        HasMany(x => x.Inventory)
            .Cascade.Delete()
            .KeyColumn("Product_id");
    }
}
public class WarehouseMap : ClassMap<Warehouse>
{
    public WarehouseMap()
    {
        Not.LazyLoad();
        Table("Warehouse");
        Id(x => x.Id, "Warehouse_id").GeneratedBy.Assigned();
        Map(x => x.Name).Column("Name").Length(10);
        HasMany(x => x.Inventory)
            .Cascade.All()
            .KeyColumn("Warehouse_id");
    }
}
public class InventoryMap : ClassMap<Inventory>
{
    public InventoryMap()
    {
        Not.LazyLoad();
        Table("Inventory");
        CompositeId()
          .KeyReference(x => x.Product, "Product_id")
          .KeyReference(x => x.Warehouse, "Warehouse_id");
        Map(x => x.StockInHand);
    }
}

我可以執行保存操作,並且可以按預期完成一半的代碼工作,但是它以常規為前提。 即,我必須了解這些對象需要保存的順序。 我尚未測試刪除操作會發生什么,但這確實意味着我必須遵循正確的順序來保存這些對象。 / *有效* / session.Save(product); session.Save(倉庫); //還將保存庫存

/* would fail */
session.Save(warehouse);
session.Save(product);

另外(我更不喜歡這樣)我可以告訴Nhibernate我想對所有事情負責。

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Not.LazyLoad();
        Table("Product");
        Id(x => x.Id, "Product_id").GeneratedBy.Assigned();
        Map(x => x.Name).Column("Name").Length(10);
        HasMany(x => x.Inventory).Inverse();
    }
}
public class WarehouseMap : ClassMap<Warehouse>
{
    public WarehouseMap()
    {
        Not.LazyLoad();
        Table("Warehouse");
        Id(x => x.Id, "Warehouse_id").GeneratedBy.Assigned();
        Map(x => x.Name).Column("Name").Length(10);
        HasMany(x => x.Inventory).Inverse();
    }
}
public class InventoryMap : ClassMap<Inventory>
{
    public InventoryMap()
    {
        Not.LazyLoad();
        Table("Inventory");
        CompositeId()
          .KeyReference(x => x.Product, "Product_id")
          .KeyReference(x => x.Warehouse, "Warehouse_id");
        Map(x => x.StockInHand);
    }
}

現在我得到以下

/* works */
session.save(Product);
session.Save(Warehouse);
session.Save(Inventory);

/* works */
session.Save(Warehouse);
session.Save(Product);
session.Save(Inventory);

/* fails */
session.Save(Inventory);
session.Save(Warehouse);
session.Save(Product);

任何人都可以對此進行改進,並給我我真正想要的映射,以便我可以保存倉庫或產品以及Fluent NHibernate,它們將使訂購正確! 例如。

session.Save(warehouse); // or session.Save(product);

這樣就導致

Insert into Warehouse... 
Insert into Product...
Insert into Inventory... // where NHibernate determines this goes last so that primary keys are in place on both previous tables!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM