EF Core与SQLite报错:尝试写入只读数据库问题排查
问题根源
异常提示"attempt to write a readonly database",且调用栈指向EF Core的AcquireDatabaseLock方法,说明加密转明文操作后,数据库文件被未释放的连接锁定,或者转换后的数据库状态异常,导致EF Core执行迁移时无法获取写权限。
修复步骤
1. 重构加密转明文方法,确保连接完全释放
当前GetDecryptedConnection方法返回打开的连接,会持续持有文件句柄,导致后续操作无法写入。改成一次性转换方法,用using自动释放连接:
private void ConvertEncryptedToPlainText(string plainTextDbPath, string encryptedDbPath) { using (var connection = new SqliteConnection($"Filename={encryptedDbPath};Mode=ReadWriteCreate")) { connection.Open(); // 参数化设置密码,避免注入和转义问题 var command = connection.CreateCommand(); command.CommandText = "PRAGMA key = @password;"; command.Parameters.AddWithValue("@password", _password); command.ExecuteNonQuery(); command.Parameters.Clear(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = "PRAGMA cipher_compatibility = 3;"; cmd.ExecuteNonQuery(); } command.CommandText = $"ATTACH DATABASE '{plainTextDbPath}' AS {PlainText} KEY '';"; command.ExecuteNonQuery(); command.CommandText = $"SELECT sqlcipher_export('{PlainText}');"; command.ExecuteScalar(); command.CommandText = $"DETACH DATABASE {PlainText};"; command.ExecuteNonQuery(); } // using块结束后,连接自动关闭,文件锁释放 }
2. 修正明文连接的初始化逻辑
转换后的明文数据库可能残留加密相关的PRAGMA设置,需要在连接时清空:
private SqliteConnection GetPlainTextConnection(string databasePath) { var connection = new SqliteConnection($"Filename={databasePath};Mode=ReadWriteCreate;"); connection.Open(); // 清空可能残留的密钥设置,确保数据库处于明文状态 using (var cmd = connection.CreateCommand()) { cmd.CommandText = "PRAGMA key = '';"; cmd.ExecuteNonQuery(); } return connection; }
3. 调整EF Core迁移触发逻辑
异常发生在Migrate阶段,说明转明文后的数据库可能缺失迁移历史表,或者EF重复执行迁移锁操作。修改EncryptedDbContext.Create()方法,避免每次实例化都执行Migrate:
public static void Create() { using (var context = new EncryptedDbContext()) { // 仅当没有已应用的迁移时才执行迁移 if (!context.Database.GetAppliedMigrations().Any()) { context.Database.Migrate(); } } }
4. 检查跨平台文件权限
虽然你确认文件系统访问正常,但转换后的明文数据库可能继承了加密数据库的权限:
- Android:确保MAUI项目的
Platforms/Android/AndroidManifest.xml中包含必要的存储权限,针对Android 10+使用Scoped Storage - iOS:在
Platforms/iOS/Info.plist中添加NSDocumentsFolderUsageDescription,说明应用需要访问Documents目录的原因
验证步骤
- 执行加密转明文操作后,重启应用(确保所有旧连接释放)
- 尝试添加多条数据,确认异常消失
- 检查明文数据库文件的读写权限是否正确
内容的提问来源于stack exchange,提问作者Bohdan
相关产品推荐
相关产品推荐

