C# Fluent NHibernate多对多加额外列不插入

C# Fluent NHibernate多对多加额外列不插入,c#,nhibernate,orm,fluent-nhibernate,C#,Nhibernate,Orm,Fluent Nhibernate,我在和来自英国的流利的nhibernate打交道 我已经复制了映射并编写了最小的程序。。。但它不会拯救。。。有人能提供一些见解吗 public class Product { public int Id { get; set; } public string Name { get; set; } public IList<Inventory> Inventory { get; set; } public Product() {

我在和来自英国的流利的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);
    }
}
我得到的例外是

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试图在仓库记录之前插入库存记录。这是因为插入的顺序由调用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.Savewarehouse放在warehouse.Inventory.Addinventory之后,那么NHibernate不会首先插入仓库记录,并抛出外键错误

最后,要获得下面列出的三条insert语句,必须在ProductMap映射类中重新安装反向语句。否则,NHibernate将发出额外的update语句

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

问题的原因是NHibernate试图在仓库记录之前插入库存记录。这是因为插入的顺序由调用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.Savewarehouse放在warehouse.Inventory.Addinventory之后,那么NHibernate不会首先插入仓库记录,并抛出外键错误

最后,要获得下面列出的三条insert语句,必须在ProductMap映射类中重新安装反向语句。否则,NHibernate将发出额外的update语句

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!)
然而,我的工作,我的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);
    }
}
或者,我更不喜欢这个,我可以告诉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);
    }
}
有谁能改进这一点,并给我提供我真正想要的映射,这样我就可以节省一个仓库或一个产品和一个流畅的NHibernate,从而获得正确的订购!?? 例如

所以这会导致

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!

对于任何可能追随我脚步的人

我的问题是,我想在链接表中存储一些有关实体之间关系的信息。通常,数据库术语中的多对多关系在域对象之间有一个链接表

根据问题中概述的结构,需要先插入仓库和产品,然后才能插入库存项目。必须最后插入一个库存项,以便在保存之前两个外键约束都已就位

Insert into Product

Insert into Warehouse

Insert into Inventory (Note this happens **after** the primary keys are 
inserted in Warehouse and Product!)
然而,我的工作,我的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);
    }
}
或者,我更不喜欢这个,我可以告诉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);
    }
}
有谁能改进这一点,并给我提供我真正想要的映射,这样我就可以节省一个仓库或一个产品和一个流畅的NHibernate,从而获得正确的订购!?? 例如

所以这会导致

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!

WarehouseMap类中存在错误。TableInventory不应该类似于TableWarehouse吗?@Penfold我已经根据您的评论更新了这个问题,我认为create table语句显示了我认为在这个场景中应该看到的内容WarehouseMap类中有一个错误。TableInventory不应该像TableWarehouse一样吗?@Penfold我已经根据你的评论更新了这个问题,我认为create table语句显示了我认为我在这个场景中应该期望的东西。你在这里说的很合理。问题是Nhiber
nate或更流畅的nhibernate需要确保键在插入到链接表之前就位,链接表具有到每个相邻表的外键链接。问题是Fluent NHibernate应该计算出这些表需要填充的顺序,即在链接表之前。在我的例子中,链接表有额外的数据来描述实体之间的关系。我很乐意接受你的答案,但我认为这是我得到的最好的答案。正如我在回答中所说,NHibernate并没有完全按照我的预期工作。看起来你碰到了一个边缘案件。NHibernate很好,但并不完美。对不起,我帮不上什么忙。不,你的回答太棒了——反映了我的想法,如果你喜欢阅读,请看下面。也许我错过了什么,也许这是悄悄地记录在某处。我会继续找的。谢谢你的输入。我遇到了这个。如果你从逻辑上考虑,在你开始将产品放入仓库之前,应该先创建仓库你在这里说的很有道理。问题是,Nhibernate或更流畅的Nhibernate需要确保键在插入到链接表之前就位,链接表具有到每个相邻表的外键链接。问题是Fluent NHibernate应该计算出这些表需要填充的顺序,即在链接表之前。在我的例子中,链接表有额外的数据来描述实体之间的关系。我很乐意接受你的答案,但我认为这是我得到的最好的答案。正如我在回答中所说,NHibernate并没有完全按照我的预期工作。看起来你碰到了一个边缘案件。NHibernate很好,但并不完美。对不起,我帮不上什么忙。不,你的回答太棒了——反映了我的想法,如果你喜欢阅读,请看下面。也许我错过了什么,也许这是悄悄地记录在某处。我会继续找的。谢谢你的输入。我遇到了这个。如果你从逻辑上考虑,在你开始将产品放入仓库之前,应该先创建仓库