簡體   English   中英

流暢的NHibernate(具有自動化)不會在多對多中保存連接表值

[英]Fluent NHibernate (with automapping) not saving join table values in many-to-many

我不是NHibernate專家,所以這可能是該部門缺乏理解。 我有兩個簡單的實體,具有多對多的關系

public class Category
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual bool Visible { get; set; }

    public virtual IList<Product> Products { get; set; }
}

public class Product
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual decimal Price { get; set; }
    public virtual bool Visible { get; set; }
    public virtual IList<Category> Categories { get; set; }
}

我的配置是

    public static void BuildFactory()
    {
        _factory = Fluently.Configure()
            .Database(
                MsSqlConfiguration
                    .MsSql2008
                    .ConnectionString(_connectionString)
                    .ShowSql()
            )
            .Mappings(m =>
                m.AutoMappings.Add(
                    AutoMap.AssemblyOf<Database>()
                        .Where(t => t.Namespace == "FancyStore.Models.Catalog")
                        .Override<Product>(k => 
                            k.HasManyToMany(x => x.Categories)
                                .Table("ProductsToCategories")
                                    .ParentKeyColumn("Product_id")
                                    .ChildKeyColumn("Category_id")
                                .Cascade.AllDeleteOrphan())
                        .Override<Category>(k =>
                            k.HasManyToMany(x => x.Products)
                                .Table("ProductsToCategories")
                                    .ParentKeyColumn("Category_id")
                                    .ChildKeyColumn("Product_id")
                                .Cascade.AllDeleteOrphan().Inverse())
                )
            )
            .ExposeConfiguration(SetConfiguration)
            .BuildConfiguration()
            .BuildSessionFactory();
    }

所以我開始時沒有覆蓋(稍后在一些谷歌搜索后添加它們),並使用ExportSchema生成我的模式。 ExportSchema知道多對多關系(即使沒有覆蓋),因為它生成了一個連接表( ProductsToCategories )。

我想添加一些簡單的測試數據,所以我這樣做了

        using (var db = new Repository<Category>())
        {
            for (int i = 0; i < 6; i++)
            {
                var cat = new Category
                {
                    Name = "Things" + i,
                    Description = "Things that are things",
                    Visible = true,
                    Products = new List<Product>()
                };

                for (int k = 0; k < 6; k++)
                {
                    var prod = new Product
                    {
                        Name = "Product" + k,
                        Description = "Product for " + cat.Name,
                        Visible = true,
                        Categories = new List<Category>(new[] { cat })
                    };
                    cat.Products.Add(prod);
                }
                db.Save(cat);
            }
        }

這樣可以正確保存產品和類別,但不會保存連接表中的任何關系。 看看sql對category.Products的調用生成,它實際上是在查找產品的連接表(並且無法找到任何,因為它是空的)

任何幫助將不勝感激 :-)

編輯 :刪除了反向,問題仍在發生:(

編輯2

以下是目錄和產品的映射文件(注意:名稱有點愚蠢,但這只是一個快速的原型 - 這種交易)

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="FancyStore.Models.Catalog.Product, FancyStore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Product`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <property name="Name" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Name" />
    </property>
    <property name="Description" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Description" />
    </property>
    <property name="Price" type="System.Decimal, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Price" />
    </property>
    <property name="Visible" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Visible" />
    </property>
    <bag cascade="all-delete-orphan" inverse="true" name="Categories" table="ProductsToCategories">
      <key>
        <column name="Product_id" />
      </key>
      <many-to-many class="FancyStore.Models.Catalog.Category, FancyStore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <column name="Category_id" />
      </many-to-many>
    </bag>
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="FancyStore.Models.Catalog.Category, FancyStore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Category`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <property name="Name" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Name" />
    </property>
    <property name="Description" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Description" />
    </property>
    <property name="Visible" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Visible" />
    </property>
    <bag cascade="all-delete-orphan" name="Products" table="ProductsToCategories">
      <key>
        <column name="Category_id" />
      </key>
      <many-to-many class="FancyStore.Models.Catalog.Product, FancyStore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <column name="Product_id" />
      </many-to-many>
    </bag>
  </class>
</hibernate-mapping>

我可能會弄錯,但看起來你把雙方的關系標記為“反向”。

您應該只為關系的一方執行此操作,並確保在另一方上調用Save

此外,我相信在保存之前雙方的關系必須是有效的(除了你已經在做的事情之外,將cat添加到prod.Categories )。

我對這些關系的理解無疑是模糊的,但這是我幾個月來的研究提出來的(並解決了我自己的一些問題)。

@Matt Briggs,我已經明白了。 您必須將一個關系設置為Inverse()並保存另一個實體,添加對兩個實體的引用(prod.Categories.Add()+ cat.Products.Add())並提交事務。 除非您提交連接表的查詢,否則不會生成。 - HeavyWave 5月13日12:43

你對關聯的錯誤方面有反過來。 反向意味着“另一方管理這種關聯”。

您需要的是刪除類別上的反轉並將其放在產品上,或將產品更改為“擁有”實體,如下所示:

//make sure to add it to BOTH sides of the association
product.Categories.Add(cat);
cat.Products.Add(product);

db.Save(cat);  //if Product has Inverse
/* or */
db.Save(prod); //if Category has Inverse

如果要在自動化之前首先應用Product和Category的流暢映射,那該怎么辦? 例如,

public class Product
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual decimal Price { get; set; }
    public virtual bool Visible { get; set; }
    public virtual IList<Category> Categories { get; set; }

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

public class ProductMap : ClassMap<Product>
{
    Id(x => x.Id);
    Map(x => x.Name);
    Map(x => x.Description);
    Map(x => x.Price);
    Map(x => x.Visible);
    HasManyToMany(x => x.Categories)
      .Table("ProductsToCategories")
      .ParentKeyColumn("Product_id")
      .ChildKeyColumn("Category_id")
      .Cascade.AllDeleteOrphan();
}

public class Category
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual bool Visible { get; set; }
    public virtual IList<Product> Products { get; set; }

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

public class CategoryMap : ClassMap<Category>
{
    Id(x => x.Id);
    Map(x => x.Name);
    Map(x => x.Description);
    Map(x => x.Visible);
    HasManyToMany(x => x.Products)
      .Table("ProductsToCategories")
      .ParentKeyColumn("Category_id")
      .ChildKeyColumn("Product_id")
      .Cascade.AllDeleteOrphan().Inverse();
}

配置,

public static void BuildFactory()
{
    _factory = Fluently.Configure()
        .Database(
            MsSqlConfiguration
                .MsSql2008
                .ConnectionString(_connectionString)
                .ShowSql()
        )
        .Mappings(m => {
            m.FluentMappings.AddFromAssemblyOf<Database>();
            m.AutoMappings.Add(
              AutoMap.AssemblyOf<Database>()
              .Where(t => t.Namespace == "FancyStore.Models.Catalog"));
        })
        .ExposeConfiguration(SetConfiguration)
        .BuildConfiguration()
        .BuildSessionFactory();
}

暫無
暫無

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

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