NHibernation: каскад не обновляет дочерние объекты - PullRequest
1 голос
/ 08 ноября 2010

Хорошо, это будет стена текста, но .... в основном, у меня есть следующие 3 класса:

public class Address
{
    public virtual int Id { get; private set; }
    public virtual string Street { get; set; }
    public virtual string POBox { get; set; }
    public virtual string ZIP { get; set; }
    public virtual string Locality { get; set; }
    public virtual Country Country { get; set; }
    public virtual ICollection<Customer> CustomersLivingHere { get; set; }
}


public class Customer
{
    public virtual int Id { get; private set; }

    public virtual string Firstname { get; set; }    
    public virtual string Lastname { get; set; }

    public virtual DateTime Birthdate { get; set; }

    public virtual ICollection<Address> Addresses { get; set; }
}

public class Country
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual string Domain { get; set; }
}

Это какая-то адресная книга (очевидно, она немного сложнее в реальном мире, но я уже сократил свои модульные тесты до этого нерабочего случая).

Адреса проверяются и нормализуются с помощью веб-службы, предоставляемой третьей стороной, поэтому в идеале я хотел бы, чтобы отношения между клиентами и адресами были многим-множественными, чтобы каждый адрес в базе данных нуждался в пройти валидацию только один раз (мы платим деньги за услугу валидации), оставаясь при этом связанным с любым количеством клиентов.

В то же время я бы хотел, чтобы NHibernate автоматически сохранял адреса, как только я назначил их объекту клиента, и сохранил их, но пока это не работает вообще.

Вот так выглядят мои файлы сопоставления для класса Customer:

public class CustomerMap : FluentNHibernate.Mapping.ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id);

        Map(x => x.Firstname).Length(256);
        Map(x => x.Lastname).Length(256);
        Map(x => x.Birthdate);

        HasMany(x => x.Addresses)
            .AsSet()
            .Inverse()
            .Cascade.All();
    }
}

... и это отображение адресов:

public class AddressMap : FluentNHibernate.Mapping.ClassMap<Address>
{
    public AddressMap()
    {
        Id(x => x.Id);
        Map(x => x.Street);
        Map(x => x.POBox);
        Map(x => x.ZIP).Length(16).Not.Nullable();
        Map(x => x.Locality).Length(128).Not.Nullable();
        References(x => x.Country).Not.Nullable();
        HasManyToMany(x => x.CustomersLivingHere)
            .Table("CustomerAddress");
    }
}

То, что я ожидаю сделать, - это просто что-то вроде:

Страна someCountry = Новая Страна { Код = "CL", DialPrefix = "+56", Имя = "Чили", Домен = ".cl" }; * 1 018 *

1020 *

Address[] Addresses = new[] {
                                new Address
                                  {
                                      Country = someCountry,
                                      Locality = "Providencia",
                                      Street = "Pasaje Anakena 123",
                                      ZIP = "7510115"
                                  },

                                new Address
                                  {
                                      Country = someCountry,
                                      Locality = "Providencia",
                                      Street = "Perez Valenzuela 1520",
                                      ZIP = "7500035"
                                  }
};



Customer[] Customers = new[] {
                             new Customer
                             {
                                     Addresses = new[] {Addresses[0], Addresses[1]},
                                     Firstname = "Jane",
                                     Lastname = "Doe"
                             }
* *} 1 022;

1025 *

using (ISession session = _sessionFactory.OpenSession())
{
    using (ITransaction transaction = session.BeginTransaction())
    {
        foreach (Customer customer in Customers)
        {
            session.Save(customer);
        }
        transaction.Commit();
    }
}

Выполнение модульного теста, содержащего код, подобный этому, в основном приводит к NHibernate.StaleStateException: Неожиданное количество строк: 0; ожидается: 1 Я прочитал около 35 записей в блоге и ТАК вопросы, но в основном они касались назначенных идентификаторов, которые я не использую - я посмотрел на файлы сопоставления, сгенерированные Fluent Hibernate, и класс генератора всегда «идентичность».

Я посмотрел на выходные данные SQL и журналы отладки NHibernate, и кажется, что NHibernate каким-то образом назначил идентификаторы некоторым объектам вместо значения по умолчанию, что приводит к тому, что NHibernate пытается выдавать UPDATE вместо операторов SELECT - я понятия не имею почему же.

Любое понимание того, как это исправить, или даже общие советы по правильному моделированию такого рода отношений, несомненно, будет оценено.

1 Ответ

2 голосов
/ 09 ноября 2010

Вы сопоставили Customer-> Address как отношение один-ко-многим (Customer HasMany Address в вашем беглом сопоставлении), а Address-> Customer как многие-ко-многим.NHibernate будет представлять Customer-> Address (HasMany) как внешний ключ CustomerId в таблице Address.Это не то, что вам нужно.

public class CustomerMap : FluentNHibernate.Mapping.ClassMap<Customer>
{
    public CustomerMap()
    {
        Id(x => x.Id);

        Map(x => x.Firstname).Length(256);
        Map(x => x.Lastname).Length(256);
        Map(x => x.Birthdate);

        HasManyToMany(x => x.Addresses)
            .Table("CustomerAddress")
            .Inverse()
            .Cascade.All();
    }
}

Этот тип двунаправленного отображения многих ко многим обсуждается в документации NHibernate здесь:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...