【问题标题】:Is there a fast way to delete all rows in a table with Castle ActiveRecord or nHibernate?有没有一种快速的方法可以使用 Castle ActiveRecord 或 nHibernate 删除表中的所有行?
【发布时间】:2012-06-15 11:02:24
【问题描述】:

我正在尝试使用 Castle ActiveRecord 删除表中的所有行。通常,我会这样做:

DB.ParseError.DeleteAll();

但是,这个表恰好有大约 190 万行。上面的命令会为表格中的每一行发出一个单独的SELECTDELETE,看起来像这样:

SELECT page0_.Id as Id29_0_, ... FROM Indexer.Pages page0_ WHERE page0_.Id=:p0;:p0 = b03665aa-37d0-4a2d-a04c-c232ebd94dbc [Type: Guid (0)]
SELECT page0_.Id as Id29_0_, ... FROM Indexer.Pages page0_ WHERE page0_.Id=:p0;:p0 = 11cb69e3-1c6a-4ac1-908b-084dfe859639 [Type: Guid (0)]
--- 1.9 million more of these
DELETE FROM Indexer.ParseErrors WHERE Id = :p0;:p0 = b03665aa-37d0-4a2d-a04c-c232ebd94dbc [Type: Guid (0)]
DELETE FROM Indexer.ParseErrors WHERE Id = :p0;:p0 = 11cb69e3-1c6a-4ac1-908b-084dfe859639 [Type: Guid (0)]
--- 1.9 million more of these

这需要......好吧,我不知道需要多长时间,因为我没有耐心让它真正完成。

我想要它做的是发出一条 SQL 语句;这个:

DELETE FROM Indexer.ParseErrors;

这是我迄今为止尝试过的:

ISessionFactoryHolder holder = ActiveRecordMediator.GetSessionFactoryHolder();
ISession session = holder.CreateSession(typeof(DB.ParseError));
IDbCommand cmd = session.Connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "DELETE FROM Indexer.ParseErrors;";
cmd.CommandTimeout = 600;
cmd.ExecuteNonQuery();
holder.ReleaseSession(session);

这似乎可行,但对我来说似乎是一种 hack,因为它完全避免了模型和 ActiveRecord 框架。另外,这可能不适用于 NHibernate 的任何缓存。

有没有更官方的方式来删除一张表,每行不做2条SQL语句?

【问题讨论】:

    标签: c# .net nhibernate castle-activerecord


    【解决方案1】:

    对于一个有这么多记录的表,你绝对不希望它为每一行创建一个实体然后删除它——这将花费很长时间。

    如果您的映射中没有定义任何未在数据库中强制执行的级联规则,那么最简单的方法是使用 SQL 查询:

    ActiveRecordBase<ParseError>.Execute(
        (s, i) => s.CreateSQLQuery("DELETE FROM ParseErrors").ExecuteUpdate(),
                                               null);
    

    这将使 NHibernate 缓存无效(因此它可以很好地与 NHibernate 二级缓存一起使用),但它不会执行任何未在 db 中定义的级联(我怀疑这对您的情况很好)。如果数据库中没有任何级联,则必须手动执行。

    如果您真的希望它使用要删除的实体,请至少使用 StatelessSessionScope,这将阻止它至少将所有实体添加到会话中。

    更新:

    Execute() 方法是 ActiveRecordBase&lt;T&gt; 的受保护成员,因此要从类外部调用它,您必须将其包装在公共静态方法中。

    【讨论】:

      【解决方案2】:

      您可以使用 nHibernate 使用以下语句从表中删除所有记录。 取决于级联规则。您可能必须先清除另一个表。

      session.Delete("from Indexer.ParseErrors p");
      

      Use full link

      【讨论】:

      • 这将导致 NHibernate 加载所有实体并一个一个地删除它们,这是他试图避免的
      【解决方案3】:

      过去每次我处理这个问题时,我都会这样做:

      session.CreateSQLQuery("DELETE FROM FOO").ExecuteUpdate();
      

      是的,它绕过了各种各样的东西,但我从来没有遇到过这个问题。

      Ayende 有一个post on this,它使用bulkcopy 来执行此操作,但似乎没有解决您对缓存的担忧。

      【讨论】:

        【解决方案4】:

        你好迈克·克里斯滕森,

        是的,有一种方法。这不是一个好方法(我认为),但它比普通 SQL 更好:

        session.CreateQuery(@"UPDATE " + typeof(?).FullName + " SET Property = :value")
               .SetParameter("value",valueVariable)
               .ExecuteUpdate();
        

        Batch Update in NHibernate

        问候 胡伊·朱卡

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多