NHibernate проблема сопоставления один ко многим - PullRequest
2 голосов
/ 14 марта 2009

Мне нужно сопоставить две простые таблицы с отношением внешнего ключа. Одна из таблиц: Контакт , содержащий столбцы идентификатор (первичный ключ типа int), имя , адрес и guid (недавно добавлено и не является первичным ключом). Другой - номер телефона , содержащий столбцы идентификатор (первичный ключ типа int), контакт ___ идентификатор (внешний ключ идентификатора в таблице контактов) и номер телефона .

Файл сопоставления для таблицы контактов выглядит следующим образом:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="OfflineDbSyncWithNHibernate" default-lazy="true" namespace="OfflineDbSyncWithNHibernate.Models">
  <class name="Contact" table="Contact">
    <id name="Id" column="Id" type="int">
      <generator class="native" />
    </id>

    <property name="Name" column="name" type="string"/>
    <property name="Address" column="address" type="string"/>
    <property name="Guid" column="guid" type="string"/>

    <set lazy="true" batch-size="6" table="phone_number" name="PhoneNumbers" fetch="join" inverse="false" cascade="all" >
      <key foreign-key="FK_contact_phone_number" column="contact_id"/>
      <one-to-many class="PhoneNumber" />
    </set>

  </class>
</hibernate-mapping>

Файл сопоставления для таблицы Phone_number:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="OfflineDbSyncWithNHibernate" default-lazy="true" namespace="OfflineDbSyncWithNHibernate.Models">
  <class name="PhoneNumber" table="phone_number">
    <id name="Id" column="Id" type="int">
      <generator class="native" />
    </id>
    <property name="ContactId" column="contact_id" />
    <property name="Number" column="phone_number" />
  </class>
</hibernate-mapping>

Классы Contact и PhoneNumber:

namespace OfflineDbSyncWithNHibernate.Models
{
    public class Contact
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string Address { get; set; }
        public virtual string Guid { get; set; }
        public virtual PhoneNumbers PhoneNumbers { get; set; }
    }
}

namespace OfflineDbSyncWithNHibernate.Models
{
    public class PhoneNumber
    {
        public virtual int Id { get; set; }
        public virtual int ContactId { get; set; }
        public virtual string Number { get; set; }
    }
}

namespace OfflineDbSyncWithNHibernate.Models
{
    public class PhoneNumbers : List<PhoneNumber>
    {
    }
}

Когда я загружаю contact и phone_numbers отдельно, он работает, но после добавления элемента set для получения отношения один ко многим nhibernate выдает ошибку:

NHibernate.MappingException: неверная информация о сопоставлении, указанная для типа OfflineDbSyncWithNHibernate.Models.Contact, проверьте файл сопоставления на предмет несоответствия типов свойств

Я новичок в nHibernate, поэтому я не уверен, есть ли ошибка в элементе set или мне даже не следует его использовать. Любая помощь будет оценена.

Ответы [ 3 ]

11 голосов
/ 29 марта 2009

Просто запомни это

  • Сумка реализована с использованием IList
  • Набор реализован с использованием ISet
  • Список реализован с использованием ArrayList или List
  • Карта реализована с использованием HashedTable или IDictionary

Если вы хотите использовать IList, используйте первое правило, т.е. измените hbm.xml, чтобы использовать Bag вместо Set, а ваш класс Phonenumbers должен наследоваться от IList, а не от List, если вы хотите использовать List, вам нужно изменить свой файл отображения на используйте список вместо Set.

3 голосов
/ 14 марта 2009

Я думаю, что ваш класс PhoneNumbers должен наследоваться от подтипа Iesi.Collections.ISet. Я не думаю, что по умолчанию в .NET предусмотрен тип «Set». См. Спящий режим FAQ

отображается на Iesi.Collections.ISet. Этот интерфейс является частью Iesi.Collections сборка распространяется с помощью NHibernate.

1 голос
/ 14 марта 2009

Тип вашей коллекции должен быть интерфейсом, потому что NHibernate предоставит свой собственный тип, который реализует этот интерфейс, когда объект извлекается из БД.

Если вы определите свою коллекцию как

public virtual ISet<PhoneNumber> Phonenumbers = new HashedSet<Phonenumber>();

Тогда я думаю, что это сработает.

Чтобы лучше контролировать доступ к вашей коллекции, вы можете изменить класс контактов следующим образом:

public class Contact
{
    public virtual int Id {get;set;}
    ..

    private ISet<Phonenumber> _phoneNumbers = new HashedSet<PhoneNumber>();

    public ReadOnlyCollection<Phonenumber> PhoneNumbers
    {
        get 
        {
           return new List<Phonenumber>(_phoneNumbers).AsReadOnly();
        }
    }

    public void AddPhonenumber( Phonenumber n )  
    {
        n.Contact = this;
        _phoneNumbers.Add(n);
    }

    public void RemovePhoneNumber( PhoneNumber n )
    {
        ...
    }
}

Затем необходимо убедиться, что при отображении класса Contact вы указываете, что NHibernate должен обращаться к полю _phoneNumbers вместо свойства PhoneNumber:

<set name="PhoneNumbers" access="field.camelcase-underscore" ... >
   ...
</set>
...