是否可以在NHibernate中初始化集合时添加多对多关系?

时间:2009-01-02 08:37:03

标签: c# nhibernate many-to-many

这是我的班级:

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 个答案:

答案 0 :(得分:2)

来自Hibernate.org

  

为什么Hibernate总是在我只想添加时初始化一个集合   或删除元素?

     

不幸的是收集API   定义可能的方法返回值   只能通过点击来计算   数据库。有三个例外   对此:Hibernate可以添加到,    或宣布   inverse =“true”而不初始化   收藏;返回值必须   永远是真的。

     

如果您想避免额外的数据库   交通(即性能关键   代码),重构您的模型只能使用   多对一协会。这是   几乎总是可能的。然后用   查询代替集合访问。

此外,阅读此博客文章NHibernate and Inverse=True|False Attribute肯定有帮助。

<强> [编辑]

好吧,想想多对一和多对一。哪一个是同一个。这就是为什么他们说重构模型。你需要引入另一个实体,比如UserFriend或者其他东西。现在,您将为User-to-UserFriend,Friend-to-UserFriend创建多对一。

因此,正如您所见,这将使它成为多对多。我希望这能使重构事情变得清晰。您可能不想这样做,除非您遇到的是真实的糟糕表现。正如Darin已经提到的那样,其中一条评论认为,不要做预先成熟的优化。此外,我想引用Donald E. Knuth臭名昭着的格言,“过早优化是所有邪恶的根源。”

答案 1 :(得分:0)

当您尝试访问Friends集合时,NHibernate将发出SELECT语句的原因是因为它在您加载用户实体时未初始化。您可以使用以下查询强制加载集合:

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。您可以根据自己的需要使用这两种方法。