Можно ли добавить отношение «многие ко многим» без инициализации коллекции в NHibernate? - PullRequest
4 голосов
/ 02 января 2009

Вот мой класс:

public class User
{
  public int Id { get; set; }
  public string Name { get; set; }

  public ISet<User> Friends { get; set; }
}

Вот мое отображение:

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

  <class name="User" table="Users">
      <id name="Id" column="id">
          <generator class="native"/>
      </id>
      <property name="Name" column="name"/>
      <set name="Friends" table="Friends">
          <key column="user_id"/>
          <many-to-many class="User" column="friend_id"/>
      </set>
  </class>
</hibernate-mapping>

Вот проблема:

User user = session.Load<User>(1);

User friend = new User();
friend.Name = "new friend";

user.Friends.Add(friend);

В последней строке [user.Friends.Add (friend)] я заметил, что она инициализирует коллекцию Friends перед добавлением в нее нового друга.

Мой вопрос: есть ли способ избежать такого поведения в NHibernate? Потому что я просто хочу, чтобы только одна команда INSERT выполнялась из соображений производительности.

Ответы [ 2 ]

2 голосов
/ 02 января 2009

Из Hibernate.org

Почему Hibernate всегда инициализирует коллекцию, когда я только хочу добавить или удалить элемент?

К сожалению API коллекций определяет возвращаемые значения метода, которые могут рассчитывается только путем нажатия на база данных. Есть три исключения к этому: Hibernate может добавить к или объявлено с обратный = "правда" без инициализации Коллекция; возвращаемое значение должно всегда будь правдой.

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

Далее, чтение этой записи в блоге NHibernate и Inverse = True | Ложный атрибут , безусловно, помогут.

[Изменено]

Ну, подумайте о многих к одному и о другом много к одному. Где один и тот же и тот же. Вот почему они сказали, чтобы рефакторинг модели. Вам нужно ввести другую сущность, скажем UserFriend или что-то еще. Теперь вы сделаете много-к-одному для друзей-друзей, друзей-друзей.

Следовательно, как вы можете видеть, это сделает его многими ко многим. Надеюсь, это прояснит ситуацию с рефакторингом. Возможно, вы не захотите этого делать, если только вы не испытываете низкую производительность на самом деле. Как уже упоминал Дарин, в одном из комментариев не делайте предварительную оптимизацию. Кроме того, я хочу процитировать этот печально известный принцип Дональда Кнута: «Преждевременная оптимизация - корень всех зол».

0 голосов
/ 02 января 2009

Причина, по которой NHibernate выдает инструкцию SELECT при попытке доступа к коллекции Friends, заключается в том, что она не была инициализирована в момент загрузки пользовательского объекта. Вы можете принудительно загрузить коллекцию, используя следующий запрос:

User user = session
    .CreateCriteria(typeof(User))
    .SetFetchMode("Friends", FetchMode.Eager)
    .Add(Expression.IdEq(1))
    .UniqueResult<User>();

или добавив fetch = "join" в файл сопоставления:

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

  <class name="User" table="Users">
      <id name="Id" column="id">
          <generator class="native"/>
      </id>
      <property name="Name" column="name"/>
      <set name="Friends" table="Friends" fetch="join">
          <key column="user_id"/>
          <many-to-many class="User" column="friend_id"/>
      </set>
  </class>
</hibernate-mapping>

Стоит отметить, что существует разница между UniqueResult и session.Load. Если пользователь не найден в базе данных, вы получите исключение ObjectNotFoundException со вторым подходом, а UniqueResult вернет значение null. Вы можете использовать любой подход в зависимости от ваших потребностей.

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