Создание и получение связанных сопоставлений в NHibernate

Скажем, у меня есть два постоянных класса Cat и Hat. Давайте представим, что связь между ними является двунаправленной «один ко многим», как у кошки может быть много разных шляп, и мы можем перемещаться по отображению в обоих направлениях. Чтобы создать связь между экземпляром каждого класса, я должен иметь возможность и исправить меня, если я ошибаюсь, сделать следующее:

Cat whiskers = new Cat();
Hat redHat = new Hat();
redHat.Id = 1; // normally assigned by generator but this makes example more explicit
whiskers.Hats.Add(redHat);
catService.Save(whiskers);
hatService.Save(redHat);

Имея это в виду, не должен ли я получить кошку, связанную с RedHat, выполнив следующие действия?

Hat hat = hatService.FindById(1); // redHat has Id 1
Cat cat = hat.Cat; // cat should be whiskers

К сожалению, когда я пытаюсь использовать эту технику, cat в последней строке получается нулевой объект. Я предполагаю, что мне что-то не хватает в моем сопоставлении «один ко многим» в Cat.hbm.xml, или, по крайней мере, я надеюсь, что это что-то настолько простое. Вот как это выглядит на данный момент:

<set name="Hats" inverse="true">
  <key column="Id"/>
  <one-to-many class="Hat"/>
</set>

У меня нет сопоставления в Hat.hbm.xml, так как добавление одного привело к ошибке «дублирующего сопоставления». Я прочитал документацию по Hibernate в сопоставлении ассоциаций, но все еще не могу заставить это работать. Что я делаю неправильно?

Полные файлы сопоставления ниже:

Cat.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="Domain"
               namespace="Domain">

  <class name="Cat" table="cats" lazy="true">

    <id name="Id">
      <generator class="increment" />
    </id>

    <property name="Name" />

    <set name="Hats" inverse="true">
      <key column="Id"/>
      <one-to-many class="Hat"/>
    </set>

  </class>

</hibernate-mapping>

Hat.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="Domain"
               namespace="Domain">

  <class name="Hat" table="hats" lazy="true">

    <id name="Id">
      <generator class="increment" />
    </id>

  </class>

</hibernate-mapping>

Изменить

Я считаю, что проблема заключалась в том, что я не инициализировал значение ISet<Hat> в классе Cat. Однако я столкнулся с новой проблемой. Когда я пытаюсь получить доступ к ассоциациям, я получаю эту ошибку:

Could not initialize proxy - no Session.

Я полагал, что этого можно было бы легко избежать, если бы я создал метод в своем DAO, где я мог бы обернуть его в такой сеанс:

public Cat GetRelatedCat(Hat hat)
{
    Cat cat;
    using (ISession session = HibernateUtil.GetSessionFactory().OpenSession())
    {
        cat = hat.Cat;
    }
    return cat;
}

Это дает ту же ошибку «нет сеанса». Я в тупике.


person Tyler Treat    schedule 12.01.2011    source источник
comment
Вы можете показать свои полные файлы сопоставления?   -  person MarioH    schedule 12.01.2011
comment
@MarioH: я обновил пост полными файлами сопоставления.   -  person Tyler Treat    schedule 13.01.2011


Ответы (2)


  1. Вам нужно добавить запись «многие к одному» в ваш файл hat.hbm. Думаю должно работать.

  2. Затем вы должны установить обе стороны ассоциации

    усы.Шляпы.Добавить(redHat);

    redHat.Cat=бакенбарды;

Я думаю, это должно заставить ваш образец работать.

Причина вашей проблемы «без сеанса» заключается в том, что прокси-сервер коллекции работает только с сеансом, с которым он был создан. Так что в вашем примере это работает только с сеансом, который создал ваш экземпляр Hat. Можно подключить прокси-сервер к другому сеансу, но обычно это не рекомендуется, поскольку это имеет сложные последствия для границ транзакций и согласованности данных.

person MarioH    schedule 13.01.2011
comment
Я добавил <many-to-one name="Cat" column="Id" cascade="all" /> в Hat.hbm, но теперь получаю Parameter index is out of range, когда пытаюсь сохранить шляпу. Кроме того, если вы можете получить доступ к прокси-серверу коллекции только с сеансом, в котором он был создан, как вы собираетесь получать сопоставления, связанные с объектом? - person Tyler Treat; 14.01.2011
comment
вам нужно использовать другое имя для столбца, потому что оно уже используется для pk. используйте что-то вроде cat_id, и это сработает. - person MarioH; 17.01.2011

Я решил проблему, создав SessionManager, который позволяет мне открывать сеанс, выполнять любые транзакции и получать доступ к любым прокси-серверам коллекции в синглтоне сеанса, а затем закрывать сеанс.

person Tyler Treat    schedule 16.01.2011