有没有一种快速的方法可以使用Castle ActiveRecord或nHibernate删除表中的所有行
本文关键字:nHibernate ActiveRecord 删除 Castle 可以使 一种 有没有 方法 | 更新日期: 2023-09-27 18:37:02
我正在尝试使用Castle ActiveRecord删除表中的所有行。 通常,我会这样做:
DB.ParseError.DeleteAll();
但是,此表中恰好有大约 190 万行。 上面的命令将要做的是为表中的每一行发出一个单独的SELECT
和DELETE
,如下所示:
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 语句?
对于具有这么多记录的表,您绝对不希望它为每一行创建一个实体,然后将其删除 - 这将需要很长时间。
如果在映射中没有定义任何未在数据库中强制执行的级联规则,则最简单的方法是使用 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中的批量更新
问候朱伊·朱卡