'Microsoft.Data.Sqlite' 意外行为
'Microsoft.Data.Sqlite' unexpected behaviour
我的代码中有一个方法,它将 sqlite3 db 初始化到指定目录,如以下代码片段所示:
using System;
using System.IO;
using Microsoft.Data.Sqlite;
namespace test
{
public static class DatabaseUtils
{
public static void InitializeDatabase(string directoryPath)
{
if (!Directory.Exists(directoryPath))
{
throw new Exception();
}
string sqliteFile = Path.Combine(Path.GetFullPath(directoryPath), "test.sqlite3");
if (File.Exists(sqliteFile))
{
throw new Exception();
}
else
{
try
{
File.Create(sqliteFile).Dispose();
using (SqliteConnection connection = new SqliteConnection($"Data Source={sqliteFile};Mode=ReadWrite"))
{
connection.Open();
using (SqliteCommand command = new SqliteCommand())
{
command.Connection = connection;
command.CommandText = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)";
command.ExecuteNonQuery();
}
connection.Close();
}
}
catch (Exception)
{
throw;
}
}
}
}
}
案例一:
第一次调用此方法时,一切都按预期进行。
这意味着 => 数据库文件是使用代码中指定的 table(MyTable) 创建的。
案例二:
第二次调用此方法时,手动删除数据库文件后,
创建数据库文件时没有在代码中指定 table(MyTable) 并发生以下错误 => SQLite Error 8: 'attempt to write a readonly database'
在我看来,好像在第一个 运行 之后没有正确处理与数据库的连接,或者在第一个 运行 期间创建的数据库以某种方式保留在内存中。
预期行为:
方法应创建指定 tables 的 sqlite 数据库文件,每次调用时,当满足上述条件时。
使用的软件包:
"Microsoft.Data.Sqlite, 版本 6.0.2",
"PowerShellStandard.Library,版本 5.1.0"
目标框架:
.NET 6
值得一提:
将 'File.Create()' 方法替换为 'Mode=ReadWriteCreate' ConnectionString 时,手动删除后不会第二次创建文件。仅在第一种方法期间 运行.
编辑:
已将 'Microsoft.Data.Sqlite' 换成 'System.Data.SQLite.Core'
现在该方法每次都按预期工作。
我想这可能是 'Microsoft.Data.Sqlite' 中的一个 BUG,或者我只是遗漏了这两个库之间的一个重要区别。
如果能得到 MSFT 开发人员关于我做错了什么的官方答复,那就太好了。
打开和关闭连接2次可能出现问题:
你可以这样试试吗:
using (SQLiteConnection connection = new SQLiteConnection($"Data Source={SqliteFile};Mode=ReadWrite"))
{
using (SQLiteCommand command = new SQLiteCommand())
{
command.Connection = connection;
command.CommandText = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)";
command.ExecuteNonQuery();
}
}
啊好的,我错过了一部分。对我来说,它总是这样工作的(简而言之):
private SQLiteConnection OpenDataBase(string dataBasePath)
{
SQLiteConnection connection = new SQLiteConnection($@"Data Source = {dataBasePath}; Version = 3; New = True; Compress = True; ");
connection.Open();
return connection;
}
public void CreateTable(string dataBasePath)
{
using (SQLiteConnection? connection = OpenDataBase(dataBasePath))
{
string create = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)"; ;
using (SQLiteCommand command = new SQLiteCommand(create, connection))
{
command.ExecuteNonQuery();
}
}
}
在 github 中深入挖掘之后,我找到了我最初问题的实际答案。有一个名为 'connection pooling' 的 feature,它导致了我在问题中描述的 'Unexpected behaviour'。
要禁用此功能,请将'Pooling=False'添加到ConnectionString,或调用'SqliteConnection.ClearAllPools()' 在你想要处理连接的地方(using 语句是不够的)。
我的代码中有一个方法,它将 sqlite3 db 初始化到指定目录,如以下代码片段所示:
using System;
using System.IO;
using Microsoft.Data.Sqlite;
namespace test
{
public static class DatabaseUtils
{
public static void InitializeDatabase(string directoryPath)
{
if (!Directory.Exists(directoryPath))
{
throw new Exception();
}
string sqliteFile = Path.Combine(Path.GetFullPath(directoryPath), "test.sqlite3");
if (File.Exists(sqliteFile))
{
throw new Exception();
}
else
{
try
{
File.Create(sqliteFile).Dispose();
using (SqliteConnection connection = new SqliteConnection($"Data Source={sqliteFile};Mode=ReadWrite"))
{
connection.Open();
using (SqliteCommand command = new SqliteCommand())
{
command.Connection = connection;
command.CommandText = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)";
command.ExecuteNonQuery();
}
connection.Close();
}
}
catch (Exception)
{
throw;
}
}
}
}
}
案例一: 第一次调用此方法时,一切都按预期进行。 这意味着 => 数据库文件是使用代码中指定的 table(MyTable) 创建的。
案例二: 第二次调用此方法时,手动删除数据库文件后, 创建数据库文件时没有在代码中指定 table(MyTable) 并发生以下错误 => SQLite Error 8: 'attempt to write a readonly database'
在我看来,好像在第一个 运行 之后没有正确处理与数据库的连接,或者在第一个 运行 期间创建的数据库以某种方式保留在内存中。
预期行为: 方法应创建指定 tables 的 sqlite 数据库文件,每次调用时,当满足上述条件时。
使用的软件包: "Microsoft.Data.Sqlite, 版本 6.0.2", "PowerShellStandard.Library,版本 5.1.0"
目标框架: .NET 6
值得一提: 将 'File.Create()' 方法替换为 'Mode=ReadWriteCreate' ConnectionString 时,手动删除后不会第二次创建文件。仅在第一种方法期间 运行.
编辑: 已将 'Microsoft.Data.Sqlite' 换成 'System.Data.SQLite.Core' 现在该方法每次都按预期工作。
我想这可能是 'Microsoft.Data.Sqlite' 中的一个 BUG,或者我只是遗漏了这两个库之间的一个重要区别。
如果能得到 MSFT 开发人员关于我做错了什么的官方答复,那就太好了。
打开和关闭连接2次可能出现问题: 你可以这样试试吗:
using (SQLiteConnection connection = new SQLiteConnection($"Data Source={SqliteFile};Mode=ReadWrite"))
{
using (SQLiteCommand command = new SQLiteCommand())
{
command.Connection = connection;
command.CommandText = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)";
command.ExecuteNonQuery();
}
}
啊好的,我错过了一部分。对我来说,它总是这样工作的(简而言之):
private SQLiteConnection OpenDataBase(string dataBasePath)
{
SQLiteConnection connection = new SQLiteConnection($@"Data Source = {dataBasePath}; Version = 3; New = True; Compress = True; ");
connection.Open();
return connection;
}
public void CreateTable(string dataBasePath)
{
using (SQLiteConnection? connection = OpenDataBase(dataBasePath))
{
string create = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)"; ;
using (SQLiteCommand command = new SQLiteCommand(create, connection))
{
command.ExecuteNonQuery();
}
}
}
在 github 中深入挖掘之后,我找到了我最初问题的实际答案。有一个名为 'connection pooling' 的 feature,它导致了我在问题中描述的 'Unexpected behaviour'。
要禁用此功能,请将'Pooling=False'添加到ConnectionString,或调用'SqliteConnection.ClearAllPools()' 在你想要处理连接的地方(using 语句是不够的)。