Проблема сопоставления "один ко многим" в NHibernate

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

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

<?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>
    {
    }
}

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

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

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


person Nazgul    schedule 14.03.2009    source источник


Ответы (3)


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

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

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

person Brijesh Mishra    schedule 29.03.2009

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

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

person Andy White    schedule 14.03.2009
comment
Спасибо, я этого не знал. Но я не собираюсь использовать здесь Set. Я хочу Список ‹PhoneNumber›. В этом случае, какой элемент я должен использовать для отображения. - person Nazgul; 14.03.2009
comment
Нет, если вам нужен список, вам нужно будет использовать сопоставление ‹bag›, поскольку ‹list› представляет собой упорядоченную коллекцию, если я не ошибаюсь. Однако сумка позволяет вам иметь несколько экземпляров одного и того же типа в вашей коллекции, и это может вызвать странные вещи, которых вы не ожидаете. - person Frederik Gheysels; 14.03.2009
comment
Ах да, верно. Я забыл об упорядочивании списком. Я обычно использую сумку. - person Andy White; 14.03.2009
comment
Попробуйте изменить свой набор на мешок в сопоставлении и измените свойство PhoneNumbers на IList ‹PhoneNumber›. Вам может не понадобиться класс PhoneNumbers. - person Andy White; 14.03.2009

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

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

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

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

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

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>
person Frederik Gheysels    schedule 14.03.2009