[英]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.