2013-03-21 105 views
2

我有两个实体Password和PasswordHash。密码包含一组PasswordHashes(这些是具有不同掩码的哈希)。NHibernate使用Cascade进行删除操作导致N + 1删除

当我删除密码时,我希望所有关联的密码哈希也被删除。

我不喜欢这样的映射:

mapping.HasMany(x => x.PasswordHashes) 
      .Cascade 
      .All() 
      .Inverse() 
      .ReferencedBy(x => x.Password); 

我预计将产生的两个查询:

DELETE FROM "PasswordHash" WHERE "IdPassword" = :p0 

和明显

DELETE FROM "Password" WHERE "IdPassword" = :p0 

相反NHibernate的产生的N + 1的查询像这样:

DELETE FROM "PasswordHash" WHERE "IdPasswordHash" = :p0 (N) 

DELETE FROM "Password" WHERE "IdPassword" = :p0 (1) 

我怎样才能改变这种行为,以更优?

编辑:代码删除:

session.Delete(password); 
session.Flush(); 
+1

您可以给出导致N + 1删除的代码吗? – mickfold 2013-03-21 10:18:37

+1

我想这个,你用来执行删除的代码,可能是有趣的:http://www.nhforge.org/doc/nh/en/index.html#performance-collections-oneshotdelete – jbl 2013-03-21 12:29:33

+0

删除HQL儿童(第一次旅行),然后删除父母?您还使用哪个数据库供应商? – Rippo 2013-03-21 14:52:13

回答

2

从我的研究,在NHibernate的(3.3)的当前版本中,它看起来是无法删除的子集用行动一个DELETE声明如域名对象上的password.hashes.Clear()session.Delete(password)。 NHibernate的文档指的是one shot deletes,但我还没有能够得到这项工作与逆和级联的单向或双向一对多关联的任何组合。

一种替代方法是使用on-delete="cascade",它禁用NHibernate中的级联功能,并将其留给数据库以强制执行级联删除。更多信息可以在this nh用户谷歌小组讨论中找到。

Rippo在评论部分提到的另一种选择是使用HQL。您需要两条语句,因此最好将它们包装在交易中,即

using (var transaction = session.BeginTransaction() 
{ 
    session.Query("delete from PasswordHash h where h.Password = :password") 
        .SetParameter("password", password) 
        .ExecuteUpdate(); 
    session.Delete(password); 
    transaction.Commit(); 
}