使用 EntityFramework 6.1 清理 Sqlite 数据库

Vacuum Sqlite database with EntityFramework 6.1

最近作为娱乐,我决定开发一个小项目来测试库 System.Data.SQLite.

提供的 EntityFramework SQlite 的好处

该应用程序有一个数据同步过程,随着时间的推移会过时,所以我决定从数据库中删除它们。正如预期的那样,删除 table 行并没有减少数据库的大小,因此我决定 运行 其中的命令 VACUUM。

读完这篇优秀的博客SQLite, VACUUM, and auto_vacuum后,一切对我来说都清楚多了,尤其是命令不能在事务内执行的事实。

Like Code First 尚不可用,我必须使用脚本在数据库中创建 tables,所以在同一个地方我执行命令。

using (var context = new Context())
{
    context.Database.CreateIfNotExists();

    context.Database.ExecuteSqlCommand(
        "CREATE TABLE IF NOT EXISTS \"main\".\"OutgoingMessages\" (\"Id\"  INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\"AccountId\"  TEXT NOT NULL ON CONFLICT ROLLBACK,\"MessageId\"  TEXT NOT NULL ON CONFLICT ROLLBACK,\"Date\"  datetime NOT NULL ON CONFLICT ROLLBACK,\"Status\"  INTEGER NOT NULL ON CONFLICT ROLLBACK,\"Content\"  BLOB NOT NULL ON CONFLICT ROLLBACK,\"Size\"  INTEGER NOT NULL ON CONFLICT ROLLBACK,\"Hash\"  TEXT NOT NULL ON CONFLICT ROLLBACK,\"Comment\"  TEXT);" +
        "CREATE TABLE IF NOT EXISTS \"main\".\"IncomingMessages\" (\"Id\"  INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\"AccountId\"  TEXT NOT NULL ON CONFLICT ROLLBACK,\"MessageId\"  TEXT NOT NULL ON CONFLICT ROLLBACK,\"Date\"  datetime NOT NULL,\"Status\"  INTEGER NOT NULL,\"Comment\"  TEXT);");

    context.Database.ExecuteSqlCommand("VACUUM;");
}

我很惊讶收到以下异常:

Additional information: SQL logic error or missing database. Cannot VACUUM from within a transaction.

An exception of type 'System.Data.SQLite.SQLiteException' occurred in EntityFramework.dll but was not handled in user code
at System.Data.SQLite.SQLite3.Reset(SQLiteStatement stmt)
at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c)

让我想到由方法 ExecuteSqlCommand 执行的所有命令都在事务中处理的原因。我正在使用 EntityFramework 6.1.3 and System.Data.Sqlite 1.0.97.0 和 .NET Framework 4.5。

问题

我错了吗?如果是这样,有没有办法执行命令?

试试这个来强制 EF 不使用事务,因为

A VACUUM will fail if there is an open transaction, or if there are one or more active SQL statements when it is run.

context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "VACUUM;");