【问题标题】:How to know how many persistent objects were deleted using Session.Delete(query);如何知道使用 Session.Delete(query) 删除了多少持久对象;
【发布时间】:2013-10-03 06:44:15
【问题描述】:

我们正在将一个项目从普通的 MySQL 查询重构为使用 NHibernate。 在 MySQL 连接器中有一个 ExecuteNonQuery 函数返回受影响的行。所以

int RowsDeleted = ExecuteNonQuery("DELETE FROM `table` WHERE ...");

会告诉我有多少行被有效删除。

如何使用 NHibernate 实现相同的目标?到目前为止,我可以看到 Session.Delete(query); 是不可能的。

我当前的解决方法是首先加载所有将要删除的对象并一个接一个地删除它们,在每次删除时增加一个计数器。但我可能会认为这会降低性能。

【问题讨论】:

    标签: c# nhibernate sql-delete


    【解决方案1】:

    如果您不介意 nHibernate 将为每一行创建删除语句,并且可能为孤立和/或其他关系创建附加语句,您可以使用 session.Delete

    为了获得更好的性能,我建议进行批量删除(参见下面的示例)。

    session.Delete

    如果您使用 session.Delete 删除许多对象,nHibernate 会确保完整性得到保留,如果需要的话,它会将所有内容加载到会话中。所以没有真正的理由来计算你的对象或有一种方法来检索已删除的对象的数量,因为你只需在运行删除之前进行查询以确定将受到影响的对象的数量......

    以下语句将按 id 删除所有 post 类型的实体。 select 语句将只查询数据库的 Id,因此它实际上非常高效......

    var idList = session.Query<Post>().Select(p => p.Id).ToList<int>();
    session.Delete(string.Format("from Post where Id in ({0})", string.Join(",", idList.ToArray())));
    

    删除的对象数量将等于列表中的 Id 数量...

    这实际上是相同的(就 nHibernate 将针对您的数据库触发的查询而言),就像您将 query&lt;T&gt; 并循环遍历结果并一一删除它们一样...

    批量删除

    您可以使用session.CreateSqlQuery 运行本机 SQL 命令。它还允许您拥有输入和输出参数。

    以下语句将按照您的预期简单地从表中删除所有内容

    session.CreateSQLQuery(@"Delete from MyTableName");
    

    要检索删除的行数,我们将使用普通的 TSQL @@ROWCOUNT 变量并通过 select 输出它。要检索选定的行数,我们必须通过AddScalar 向创建的查询添加一个输出参数,UniqueResult 简单地返回整数:

    var rowsAffected = session.CreateSQLQuery(@"
            Delete from MyTableName; 
            Select @@ROWCOUNT as NumberOfRows")
        .AddScalar("NumberOfRows", NHibernateUtil.Int32)
        .UniqueResult();
    

    要传递输入变量,您可以使用.SetParameter(&lt;name&gt;,&lt;value&gt;)

    var rowsAffected = session.CreateSQLQuery(@"
            DELETE from MyTableName where ColumnName = :val; 
            select @@ROWCOUNT NumberOfRows;")
         .AddScalar("NumberOfRows", NHibernateUtil.Int32)
         .SetParameter("val", 1)
         .UniqueResult();
    

    我对 MySQL 不太满意,我写的示例是针对 MSSQL 的,我认为在 MySQL 中,@@ROWCOUNT 等价于 SELECT ROW_COUNT();

    【讨论】:

    • 感谢您最有用的回答。但是,它使应用程序数据库类型依赖,或者应该为 NHibernate 支持的每种数据库类型编写查询,并检查在运行时使用哪种方言。我希望有一种更优雅的方式。不过你的回答很有价值。
    • 实际上没有,除了使用普通的 sql 对象并完全忽略 nHibernate 之外,没有其他方法可以一次性删除。如果您使用普通 session.Delete 或同时删除多个实体,nHibernate 将始终检索关系,并可能为您删除孤儿或交叉表条目。这很酷,但它总是会一个一个地做...... NHibernate 根本不是为了做批处理操作......
    • @MikedeKlerk 我已经用另一个示例更新了答案的开头,并解释了为什么使用 session.Delete 时不需要任何计数器...
    猜你喜欢
    • 2010-11-11
    • 2014-06-12
    • 2011-11-18
    • 2023-03-16
    • 2011-02-03
    • 1970-01-01
    • 2011-02-21
    • 2016-07-16
    相关资源
    最近更新 更多