NHibernate中的多对多关系(Fluent NHibernat)在数据库中创建意外记录

本文关键字:数据库 创建 意外 记录 Fluent 关系 NHibernate NHibernat | 更新日期: 2023-09-27 18:25:09

我正在使用Fluent NHibernate处理商店和产品之间的多对多关系。我不会发布实体,因为它无关紧要。这些是我的映射

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentNHibernate.Mapping;
using FluentNHibernateSample.Domain;
namespace FluentNHibernateSample.Mappings
{
    public class ProductMap : ClassMap<Product>
    {
        public ProductMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            Map(x => x.Price);
            HasManyToMany(x => x.Stores).Cascade.All().
                Table("StoreProduct").ParentKeyColumn("ProductId")
                .ChildKeyColumn("StoreId");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentNHibernate.Mapping;
using FluentNHibernateSample.Domain;
namespace FluentNHibernateSample.Mappings
{
    public class StoreMap : ClassMap<Store>
    {
        public StoreMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            HasMany(x => x.Staff).KeyColumn("StoreId").Cascade.All();
            HasManyToMany(x => x.Products).Cascade.All().
                Table("StoreProduct").
                ParentKeyColumn("StoreId").ChildKeyColumn("ProductId");
        }
    }
}

这是我尝试在数据库中插入记录的示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernateSample.Domain;
namespace FluentNHibernateSample
{
    class Program
    {
        static void Main(string[] args)
        {
            ISessionFactory sessionFactory = CreateSessionFactory();
            using (var session = sessionFactory.OpenSession())
            {
                session.Transaction.Begin();
                Store store = new Store();
                store.Name = "Emall";
                Product product = new Product();
                product.Name = "Emall Item 1";
                product.Price = 12.5;
                //Sample code below
                session.Save(store);
                session.Transaction.Commit();
                Console.ReadKey();
            }
        }
        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure().
                    Database(MsSqlConfiguration.MsSql2008.
                        ConnectionString( m => m.FromConnectionStringWithKey(System.Environment.MachineName))).
                    Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>()).
                        BuildSessionFactory();
        }
    }
}

样本代码:

            //option 1 ==> doesn't work
            product.Stores.Add(store);
            //option 2 ==> works
            store.Products.Add(product);
            //option 3 ==> creates 2 entries in Junction table
            product.Stores.Add(store);
            store.Products.Add(product);

为什么第二个选项有效,而第一个选项无效?我理解这种情况的发生是因为我正在将商店添加到产品中并保存商店。但是,由于对象跟踪,第一个选项不应该也起作用吗?此外,第三个选项在连接表中创建了2条记录,这让我大吃一惊。我该如何解决这个问题?映射类有什么错误吗?

NHibernate中的多对多关系(Fluent NHibernat)在数据库中创建意外记录

双向manytomy的一侧必须负责关联,这意味着可以负责插入链接记录。没有回应的一方必须说.Inverse()来告诉NH另一方有责任。

// for example
HasManyToMany(x => x.Products).Inverse()

更新:为了保持一致,你总是需要使用option 3,否则它会在数据库中连接,但不会在内存中连接,这会导致的细微错误

// in Store
public virtual void Add(Product product)
{
    if(!Products.Contains(product))
    {
        Products.Add(product);
        product.Add(this);
    }
}
// in Product
public virtual void Add(Store store)
{
    if(!Stores.Contains(store))
    {
        Stores.Add(store);
        store.Add(this);
    }
}