2010-11-08 1 views
1

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

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 = new Страна { Код = "CL", DialPrefix = "+56", Название = "Чили", Домен = ".cl" };

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" 
          } 

};

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 записей в блоге и вопросов SO, но те, которые в основном касались назначенных идентификаторов, которые я не использую, я просмотрел файлы сопоставления, созданные Fluent Hibernate, и класс генератора всегда «идентичен» ».

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

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

+0

И кошмары, как это почему после работы с NHibernate в течение многих лет, я у него было почти полное выпадение с ним. Я бы порекомендовал размещение в группе пользователей NH и группы пользователей FluentNHibernate, так как вы могли бы получить помощь от гуру NH. –

ответ

2

Вы сопоставили Customer-> Address как отношение «один ко многим» (адрес клиента HasMany в вашем свободном сопоставлении), но 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 здесь:

http://nhibernate.info/doc/nh/en/index.html#collections-bidirectional