有没有一种快速方法可以使用Castle ActiveRecord或nHibernate删除表中的所有行?

时间:2012-06-14 05:40:02

标签: c# .net nhibernate castle-activerecord

我正在尝试使用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);

这似乎有效,但对我来说这似乎是一个黑客,因为它完全避免了模型和ActiveRecord框架。另外,这可能不适合NHibernate的任何缓存。

是否有更多官方删除表的方法,而不是每行执行2条SQL语句?

4 个答案:

答案 0 :(得分:3)

对于包含那么多记录的表,你绝对不希望它为每一行创建一个实体然后删除它 - 它将需要永远。

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

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

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

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

<强>更新

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

答案 1 :(得分:1)

您可以使用以下语句删除带有nHibernate的表中的所有记录。 取决于级联规则。您可能需要先清除其他表格。

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

Use full link

答案 2 :(得分:1)

每次我在过去处理过这个问题时,我都做过类似的事情:

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

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

Ayende有post on this使用批量复制来做这件事,但似乎并没有解决你对缓存的担忧。

答案 3 :(得分:0)

Hello Mike Christensen,

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

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

Batch Update in NHibernate

问候 Juy Juka