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

本文关键字:nHibernate ActiveRecord 删除 Castle 可以使 一种 有没有 方法 | 更新日期: 2023-09-27 18:37:02

我正在尝试使用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 语句?

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

对于具有这么多记录的表,您绝对不希望它为每一行创建一个实体,然后将其删除 - 这将需要很长时间。

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

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

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

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

更新:

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

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

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

使用完整链接

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

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

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

Ayende有一篇关于此的帖子,它使用批量复制来做到这一点,但似乎没有解决您对缓存的担忧。

你好迈克·克里斯滕森,

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

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

NHibernate中的批量更新

问候朱伊·朱卡