如何在 winforms 中查找和关闭任何打开的 OleDbConnections?
How to find and close any open OleDbConnections in winforms?
首先:我已经看到很多关于这个主题的堆栈讨论(以及在其他论坛上)。 它不是重复的。我尝试了很多建议都无济于事。
我有一个大而复杂的 c# winforms 应用程序。由于各种原因,它会在不同时间与 Access 数据库建立 OleDB 连接。在某个函数中我们需要MOVE(复制+删除)mdb文件,但是因为它被锁定了所以无法完成。我对 unlock/release mdb 文件尝试了很多不同的方法,有时它会起作用。但在某种100%可重现的场景下,是无法解锁的。我们有 2 个全局 oledb 连接变量,我们在任何地方重复使用,以提高效率,并避免在任何地方都有 1-off 连接。这两个连接变量在我们想要关闭连接时很有用,所以我们可以删除 mdb。
这是我的功能(通常有效 - 只是在这 1 种情况下无效)强制 close/release 来自我们的 winforms 应用程序的 2 个 oledb 连接:
public static void CloseOleDBConnections(bool forceReleaseAll = false) {
if ( DCGlobals.Connection1 != null )
DCGlobals.Connection1.Close();
if ( DCGlobals.Connection2 != null )
DCGlobals.Connection2.Close();
if ( forceReleaseAll ) {
DCGlobals.Connection1.Dispose();
DCGlobals.Connection2.Dispose();
OleDbConnection.ReleaseObjectPool();
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
}
}
我将 true 传递给上面的函数。
小小的帮助:请不要浪费时间说 Access 不好、不可扩展等。我知道它不好而且不可扩展,但这是一个遗留要求,我们现在坚持使用它。谢谢。
另一个想法:当然,我的 winforms 应用程序知道所有打开的 oledb 连接。有没有办法告诉 c# 查找和迭代所有打开的连接?当我 close/exit 我的应用程序时 - 噗 - 与 mdb 的打开连接被释放,我可以删除该文件。所以 .net 中的某些东西知道连接并知道如何释放它 - 那么我如何在不退出应用程序的情况下利用相同的逻辑?
有什么想法吗?
Disposed IDataReaders?
您是否正确禁用了所有 IDataReader 对象?它们可能会阻止连接正常关闭。
跟踪解决方案
无论如何,您至少需要更好地跟踪所有连接。这听起来像一个非常大的项目。您需要绝对确定所有连接都已处理。
1.新建 TrackedOleDbConnection 对象
创建一个继承自OleDbConnection 的TrackedOleDbConnection 对象,但添加了一个名为StillOpen 的静态ConcurrentList。当构造 TrackedOleDbConnection 时,将其添加到列表中,当它被处置(覆盖该函数)时,将其删除。
public class TrackedOleDbConnection: OleDbConnection
{
public TrackedOleDbConnection() : base()
{
}
public TrackedOleDbConnection(string ConnectionString) : base(ConnectionString)
{
}
//You don't need to create a constructor for every overload of the baseclass, only for overloads your project uses
ConcurrentList<TrackedOleDbConnection> ActiveConnections = new ConcurrentList<TrackedOleDbConnection>();
void AddActiveConnection()
{
ActiveConnections.Add(this);
}
override void Dispose()
{
ActiveConnections.RemoveIfExists(this); //Pseudo-function
GC.SuppressFinalise(this);
}
//Destructor, to ensure the ActiveConnection is always removed, if Dispose wasn't called
~TrackedOleDbConnection()
{
//TODO: You should log when this function runs, so you know you still have missing Dispose calls in your code, and then find and add them.
Dispose();
}
}
2。不要再直接引用 OleDbConnection
然后在您的解决方案中执行简单的查找和替换以使用 TrackedOleDbConnection。
最后,在您的 CloseOleDBConnections 函数期间,您可以访问 TrackedOleDbConnection.StillOpen 以查看您是否在某处遇到未跟踪连接的问题。
无论您在哪里发现此类未跟踪的问题,都不要使用单一的中央引用,而是 using
以确保正确处理您的连接。
可能如果您唯一需要的是复制文件,则可能不需要弄乱连接。请看这个:
https://www.raymond.cc/blog/copy-locked-file-in-use-with-hobocopy/
ADOX 很可能没有释放与数据库的连接。确保您:
- 显式调用 'Close' ADOX 连接对象
- 打电话给 'Dispose' 他们
- 调用 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(db.ActiveConnection);
- 呼叫System.Runtime.InteropServices.Marshal.Marshal.FinalReleaseComObject(db);
- 将它们设置为 Nothing/null
此外,当某些东西在文件句柄上调用关闭时,关闭请求将放入队列中以供内核处理。换句话说,即使关闭一个简单的文件也不会立即发生。为此,您可能必须放入一个限时循环来检查 .LDB 文件是否已删除……尽管这最终需要用户等待。寻求此方法的任何其他替代方法,尽管过去有必要使用其他 formats/connections IME。
首先:我已经看到很多关于这个主题的堆栈讨论(以及在其他论坛上)。 它不是重复的。我尝试了很多建议都无济于事。
我有一个大而复杂的 c# winforms 应用程序。由于各种原因,它会在不同时间与 Access 数据库建立 OleDB 连接。在某个函数中我们需要MOVE(复制+删除)mdb文件,但是因为它被锁定了所以无法完成。我对 unlock/release mdb 文件尝试了很多不同的方法,有时它会起作用。但在某种100%可重现的场景下,是无法解锁的。我们有 2 个全局 oledb 连接变量,我们在任何地方重复使用,以提高效率,并避免在任何地方都有 1-off 连接。这两个连接变量在我们想要关闭连接时很有用,所以我们可以删除 mdb。
这是我的功能(通常有效 - 只是在这 1 种情况下无效)强制 close/release 来自我们的 winforms 应用程序的 2 个 oledb 连接:
public static void CloseOleDBConnections(bool forceReleaseAll = false) {
if ( DCGlobals.Connection1 != null )
DCGlobals.Connection1.Close();
if ( DCGlobals.Connection2 != null )
DCGlobals.Connection2.Close();
if ( forceReleaseAll ) {
DCGlobals.Connection1.Dispose();
DCGlobals.Connection2.Dispose();
OleDbConnection.ReleaseObjectPool();
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
}
}
我将 true 传递给上面的函数。
小小的帮助:请不要浪费时间说 Access 不好、不可扩展等。我知道它不好而且不可扩展,但这是一个遗留要求,我们现在坚持使用它。谢谢。
另一个想法:当然,我的 winforms 应用程序知道所有打开的 oledb 连接。有没有办法告诉 c# 查找和迭代所有打开的连接?当我 close/exit 我的应用程序时 - 噗 - 与 mdb 的打开连接被释放,我可以删除该文件。所以 .net 中的某些东西知道连接并知道如何释放它 - 那么我如何在不退出应用程序的情况下利用相同的逻辑?
有什么想法吗?
Disposed IDataReaders?
您是否正确禁用了所有 IDataReader 对象?它们可能会阻止连接正常关闭。
跟踪解决方案
无论如何,您至少需要更好地跟踪所有连接。这听起来像一个非常大的项目。您需要绝对确定所有连接都已处理。
1.新建 TrackedOleDbConnection 对象
创建一个继承自OleDbConnection 的TrackedOleDbConnection 对象,但添加了一个名为StillOpen 的静态ConcurrentList。当构造 TrackedOleDbConnection 时,将其添加到列表中,当它被处置(覆盖该函数)时,将其删除。
public class TrackedOleDbConnection: OleDbConnection
{
public TrackedOleDbConnection() : base()
{
}
public TrackedOleDbConnection(string ConnectionString) : base(ConnectionString)
{
}
//You don't need to create a constructor for every overload of the baseclass, only for overloads your project uses
ConcurrentList<TrackedOleDbConnection> ActiveConnections = new ConcurrentList<TrackedOleDbConnection>();
void AddActiveConnection()
{
ActiveConnections.Add(this);
}
override void Dispose()
{
ActiveConnections.RemoveIfExists(this); //Pseudo-function
GC.SuppressFinalise(this);
}
//Destructor, to ensure the ActiveConnection is always removed, if Dispose wasn't called
~TrackedOleDbConnection()
{
//TODO: You should log when this function runs, so you know you still have missing Dispose calls in your code, and then find and add them.
Dispose();
}
}
2。不要再直接引用 OleDbConnection
然后在您的解决方案中执行简单的查找和替换以使用 TrackedOleDbConnection。
最后,在您的 CloseOleDBConnections 函数期间,您可以访问 TrackedOleDbConnection.StillOpen 以查看您是否在某处遇到未跟踪连接的问题。
无论您在哪里发现此类未跟踪的问题,都不要使用单一的中央引用,而是 using
以确保正确处理您的连接。
可能如果您唯一需要的是复制文件,则可能不需要弄乱连接。请看这个:
https://www.raymond.cc/blog/copy-locked-file-in-use-with-hobocopy/
ADOX 很可能没有释放与数据库的连接。确保您:
- 显式调用 'Close' ADOX 连接对象
- 打电话给 'Dispose' 他们
- 调用 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(db.ActiveConnection);
- 呼叫System.Runtime.InteropServices.Marshal.Marshal.FinalReleaseComObject(db);
- 将它们设置为 Nothing/null
此外,当某些东西在文件句柄上调用关闭时,关闭请求将放入队列中以供内核处理。换句话说,即使关闭一个简单的文件也不会立即发生。为此,您可能必须放入一个限时循环来检查 .LDB 文件是否已删除……尽管这最终需要用户等待。寻求此方法的任何其他替代方法,尽管过去有必要使用其他 formats/connections IME。