Val*_*lli 36 c# sqlite system.data.sqlite
我在ASP.NET应用程序(框架4.0)中使用System.Data.SQLite提供程序.我遇到的问题是,当我在SQLite数据库的表中插入某些内容时,数据库会被锁定,即使在连接处理后锁也没有被释放.
尝试访问该文件时,错误是:"进程无法访问文件'catalog.sqlite',因为它正由另一个进程使用."
我的代码非常简单,我打开连接,从SQLServer数据库读取一些数据,将数据插入SQLite(通过SQLiteDataAdapter),然后关闭连接并处置所有内容以保证安全.但是,当我在填充数据后尝试压缩文件时,我得到了这个错误.
我已经在StackOverflow上阅读了所有类型的建议,但没有一个能帮助解决问题(关闭防病毒软件,更改事务模型,在压缩文件之前等待几秒钟,将所有插入调用包装到事务中,等等.但没有人帮助解决这个问题.
也许有一些特定于ASP.NET的东西(多线程是问题?即使我在开发机器上测试它,只有一个调用该函数而没有并发?)
作为旁注,我尝试避免使用DataTable和SQLiteDataAdapter,并且直接使用SQLiteCommand,这样就可以实现魅力.当然,我可以继续将查询构建为字符串而不是使用数据适配器,但是当有一个构建框架时,我发现它有点尴尬.
edy*_*mtt 36
我使用随1.0.82.0 System.Data.Sqlite.dll版附带的设计器生成的数据集/ tableadapter遇到了同样的问题- 在关闭连接后,我们无法使用读取数据库文件System.IO.FileStream.我正确处理连接和tableadapters,我没有使用连接池.
根据我的第一次搜索(例如这个和这个线程),这似乎是库本身的问题 - 对象未正确发布和/或汇集问题(我不使用).
在阅读了你的问题之后,我试图仅使用SQLiteCommand对象来复制问题,并且我发现当你不处理它们时会出现问题.更新2012-11-27 19:37 UTC:System.Data.SQLite 的此票证进一步确认了这一点,其中开发人员解释说" 所有与连接相关的SQLiteCommand和SQLiteDataReader对象[应该]正确处理".
然后我转回生成的TableAdapters,我发现没有该Dispose方法的实现- 所以实际上创建的命令没有被处理掉.我实现了它,负责处理所有命令,我没有遇到任何问题.
这是C#中的代码,希望这会有所帮助.请注意,代码是从Visual Basic中的原始代码转换而来的,因此需要一些转换错误.
//In Table Adapter
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Common.DisposeTableAdapter(disposing, _adapter, _commandCollection);
}
public static class Common
{
/// <summary>
/// Disposes a TableAdapter generated by SQLite Designer
/// </summary>
/// <param name="disposing"></param>
/// <param name="adapter"></param>
/// <param name="commandCollection"></param>
/// <remarks>You must dispose all the command,
/// otherwise the file remains locked and cannot be accessed
/// (for example, for reading or deletion)</remarks>
public static void DisposeTableAdapter(
bool disposing,
System.Data.SQLite.SQLiteDataAdapter adapter,
IEnumerable<System.Data.SQLite.SQLiteCommand> commandCollection)
{
if (disposing) {
DisposeSQLiteTableAdapter(adapter);
foreach (object currentCommand_loopVariable in commandCollection)
{
currentCommand = currentCommand_loopVariable;
currentCommand.Dispose();
}
}
}
public static void DisposeSQLiteTableAdapter(
System.Data.SQLite.SQLiteDataAdapter adapter)
{
if (adapter != null) {
DisposeSQLiteTableAdapterCommands(adapter);
adapter.Dispose();
}
}
public static void DisposeSQLiteTableAdapterCommands(
System.Data.SQLite.SQLiteDataAdapter adapter)
{
foreach (object currentCommand_loopVariable in {
adapter.UpdateCommand,
adapter.InsertCommand,
adapter.DeleteCommand,
adapter.SelectCommand})
{
currentCommand = currentCommand_loopVariable;
if (currentCommand != null) {
currentCommand.Dispose();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新2013-07-05 17:36 UTC gorogm的回答强调了两件重要的事情:
根据System.Data.SQLite官方网站上的更改日志,从版本1.0.84.0开始,不需要上面的代码,因为库负责处理这个问题.我没有测试过这个,但在最坏的情况下你只需要这个片段:
//In Table Adapter
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
this.Adapter.Dispose();
}
Run Code Online (Sandbox Code Playgroud)关于Dispose调用的实现TableAdapter:最好将它放在一个部分类中,这样数据集的重新生成不会影响这个代码(以及你可能需要添加的任何其他代码).
kla*_*dze 26
我也有同样的问题.我的方案是在获取SQLite数据库文件中的数据之后我想删除该文件,但它总是抛出错误" ......使用其他进程 ".即使我处理SqliteConnection或SqliteCommand仍然会发生错误.我通过调用修复了错误GC.Collect().
代码段
public void DisposeSQLite()
{
SQLiteConnection.Dispose();
SQLiteCommand.Dispose();
GC.Collect();
}
Run Code Online (Sandbox Code Playgroud)
希望这有帮助.
Nat*_*ate 10
在我的情况下,我在SQLiteCommand没有明确处理它们的情况下创建对象.
var command = connection.CreateCommand();
command.CommandText = commandText;
value = command.ExecuteScalar();
Run Code Online (Sandbox Code Playgroud)
我把我的命令包装在一个using声明中,它解决了我的问题.
static public class SqliteExtensions
{
public static object ExecuteScalar(this SQLiteConnection connection, string commandText)
{
// Added using
using (var command = connection.CreateCommand())
{
command.CommandText = commandText;
return command.ExecuteScalar();
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它
connection.ExecuteScalar(commandText);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
38152 次 |
| 最近记录: |