这是我的班级:
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命令。
答案 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。您可以根据自己的需要使用这两种方法。