Отношение многие ко многим в NHibernate (Fluent NHibernate) создает неожиданные записи в базе данных - PullRequest
2 голосов
/ 19 февраля 2012

Я использую 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);

ПочемуВторой вариант работает, а первый нет?Я понимаю, что это происходит потому, что я добавляю магазин в продукт и сохраняю магазин.Но не должен ли 1-й вариант работать из-за отслеживания объекта?Далее, третий вариант полностью удивляет меня, создав 2 записи в соединительной таблице.Как я могу решить эту проблему?Что-то не так в классах отображения?

1 Ответ

1 голос
/ 20 февраля 2012

одна сторона двунаправленного множества должна быть той, которая отвечает за ассоциацию, что означает возможность вставки связывающих записей. Безответственная сторона должна сказать .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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...