在 MS 访问文件上使用 dispose 和 SuppressFinalize 后文件已在使用中的异常
Posted
技术标签:
【中文标题】在 MS 访问文件上使用 dispose 和 SuppressFinalize 后文件已在使用中的异常【英文标题】:file already in use exception after using dispose and SuppressFinalize on MS access File 【发布时间】:2016-04-07 15:35:20 【问题描述】:我正在开发通过 GUI 对数据库进行更改的软件。我想在用户单击保存后压缩数据库。保存后用户可以继续使用软件或关闭,所以我没有使用“使用”。我创建了 databaseAccess 对象,它与其他几个对象一起保存 OleDbConnection 连接对象。这是我的数据库访问类。
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
namespace TreeTool
public class DataBaseAccess
#region Properties
private string m_directory;
public List<string> selectedTableNames;
private Dictionary<String, DataTable> selectedTables;
private OleDbConnection mdbConnection;
DataTable dataTable;
//Constructor
public DataBaseAccess()
selectedTableNames = new List<string>();
selectedTables = new Dictionary<string, DataTable>();
public string directory
get
return m_directory;
set
m_directory = value;
#endregion
public List<string> GetAllTableNames()
if (dataTable != null)
List<string> tableList = new List<string>();
for (int i = 0; i < dataTable.Rows.Count; i++)
string TableName = dataTable.Rows[i][2].ToString();
tableList.Add(TableName);
return tableList;
return null;
/// <summary>
/// Returns Table Columns
/// </summary>
/// <returns></returns>
public DataTable GetTable(string TableName)
DataTable mdbTable;
if (selectedTables.TryGetValue(TableName, out mdbTable))
return mdbTable;
else
mdbTable = new DataTable();
//mdbConnection.Open();
string mdbCommandString = "SELECT * FROM [" + TableName + "]";
OleDbDataAdapter QueryCommand = new OleDbDataAdapter(mdbCommandString, mdbConnection);
QueryCommand.Fill(mdbTable);
//mdbConnection.Close();
selectedTables.Add(TableName, mdbTable);
return mdbTable;
public void SetTable(String TableName, DataTable dataTable)
//mdbConnection.Open();
OleDbCommand ac = new OleDbCommand("delete from [" + TableName + "]", mdbConnection);
ac.ExecuteNonQuery();
foreach (DataRow row in dataTable.Rows)
String query = "INSERT INTO [" + TableName + "] (TaskID, htmlTopic, nRelative, [Group], nKey,"
+ " [nText], nImage, nSelImage, nFontName, nFontInfo, Keywords) VALUES (@TaskID,"
+ " @HTMLTopic, @nRelative, @Group, @nKey, @nText, @nImage, @nSelImage, @nFontName, "
+ " @nFontInfo, @Keywords)";
OleDbCommand command = new OleDbCommand(query, mdbConnection);
command.Parameters.AddWithValue("@TaskID", row["TaskID"]);
command.Parameters.AddWithValue("@HTMLTopic", row["HTMLTopic"]);
command.Parameters.AddWithValue("@nRelative", row["nRelative"]);
command.Parameters.AddWithValue("@Group", row["Group"]);
command.Parameters.AddWithValue("@nKey", row["nKey"]);
command.Parameters.AddWithValue("@nText", row["nText"]);
command.Parameters.AddWithValue("@nImage", row["nImage"]);
command.Parameters.AddWithValue("@nSelImage", row["nSelImage"]);
command.Parameters.AddWithValue("@nFontName", row["nFontName"]);
command.Parameters.AddWithValue("@nFontInfo", row["nFontInfo"]);
command.Parameters.AddWithValue("@Keywords", row["Keywords"]);
command.ExecuteNonQuery();
//mdbConnection.Close();
internal bool validTable(string TableName)
DataTable mdbTable = new DataTable();
//mdbConnection.Open();
string mdbCommandString = "SELECT * FROM [" + TableName + "]";
OleDbDataAdapter QueryCommand = new OleDbDataAdapter(mdbCommandString, mdbConnection);
QueryCommand.Fill(mdbTable);
//mdbConnection.Close();
// check if table contains all columns necessary
String[] columnNames = new string[] "TaskID" , "HTMLTopic", "nRelative", "Group", "nKey",
"nText", "nImage", "nSelImage", "nFontName", "nFontInfo", "Keywords";
Boolean missingColumn = false;
DataColumnCollection columns = mdbTable.Columns;
foreach (String columnName in columnNames)
if (columns.Contains(columnName) == false)
// print the message
MessageBox.Show("Database: " + directory + " Table: " + TableName + " is missing column \"" + columnName
+ "\". Add it to make changes.",
"Missing column",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
missingColumn = true;
if (missingColumn == true)
return false;
return true;
public void insertTable(String tableName)
selectedTableNames.Add(tableName);
public List<String> getSelectedTables()
return selectedTableNames;
public Boolean isConnected()
if (mdbConnection == null)
return false;
return true;
public void connect()
if (mdbConnection == null)
String m_mdbDirectory = @"Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + m_directory;
mdbConnection = new OleDbConnection(m_mdbDirectory);
mdbConnection.Open();
string[] restrictions = new string[4];
restrictions[3] = "Table";
dataTable = mdbConnection.GetSchema("TABLES", restrictions);
//mdbConnection.Close();
public void disconnect()
mdbConnection.Close();
mdbConnection.Dispose();
GC.SuppressFinalize(mdbConnection);
mdbConnection = null;
public void clearSelectedTables()
selectedTableNames.Clear();
保存和压缩功能是这样的
private void save()
foreach(DataBaseAccess database in databases)
// save changes code
database.disconnect();
CompactAndRepairAccessDB(database.directory);
database.connect();
private void CompactAndRepairAccessDB(string accessFile)
string tempFile = @"temp.mdb";
FileInfo temp = new FileInfo(tempFile);
// Required COM reference for project:
// Microsoft Office 14.0 Access Database Engine Object Library
var dbe = new Microsoft.Office.Interop.Access.Dao.DBEngine();
try
dbe.CompactDatabase(accessFile, tempFile);
temp.CopyTo(accessFile, true);
temp.Delete();
catch (Exception e)
Console.WriteLine("Error: " + e.Message);
异常发生在“dbe.CompactDatabase(accessFile, tempFile);”行。
【问题讨论】:
错误发生在代码的哪一部分? dbe.CompactDatabase(accessFile, tempFile); 你为什么使用GC.SuppressFinalize
?为什么不希望调用 Finalizer?
为什么connect()
调用mdbConnection.Close();
和disconnect()
呢?在 connect 函数中将 mdbConnection.Close();
注释掉后,对我来说一切正常。
你确定不是 temp.mdb 被锁定了吗? - 可能值得使用 System.IO.Path.GetTempFileName() 来消除它。也可能值得在调用 CompactDatabase 之前显式处理所有 DataTable、OleDbDataAdapter 和 OleDbCommand 对象(或清除所有引用并显式调用 System.GC.Collect()),以查看这是否会改变行为。
【参考方案1】:
在您使用OleDbDataAdapter
和OleDbCommand
的所有方法的代码中,请确保对这些对象使用 using-Pattern。即使实际连接已经释放,他们也可以保持 mdb 文件打开。
需要修改的方法好像是GetTable
、SetTable
和ValidTable
。
【讨论】:
在 OleDbDataAdapter 和 OleDbCommand 上使用“使用”有效。谢谢。以上是关于在 MS 访问文件上使用 dispose 和 SuppressFinalize 后文件已在使用中的异常的主要内容,如果未能解决你的问题,请参考以下文章
在 dispose 方法中访问 BlocProvider.of<Bloc>(context)