4

我一直在使用SQL Server CE 3.5 SP2数据库的.NET CF应用程序中发现这个随机问题。存在文件共享冲突。 SQL Server CE 3.5 SP2

当CF应用程序启动时,它执行数据库维护验证.SDF数据库文件使用SQL Server CE Engine类检查:

using (SqlCeEngine engine = new SqlCeEngine(Resources.SqlCeConnectionString)) 
{ 
    Log.Info("Starting database Verification."); 

    if (!engine.Verify()) 
    { 
     Log.Warn("Database failed verification."); 
     engine.Repair(null, RepairOption.RecoverAllOrFail); 
     Log.Info("Database successfully repaired."); 
    } 
    else 
    { 
     Log.Info("Database Verification successful."); 
    } 
} 

如果应用程序验证正确的话,我复制.SDF成备份文件夹:

if (File.Exists(Resources.DatabaseFileLocation)) 
{ 
    File.Delete(Resources.BackupDatabaseFileLocation); 
    File.Copy(Resources.DatabaseFileLocation, Resources.BackupDatabaseFileLocation); 
    Log.Info("Database backup complete."); 
} 
else 
{ 
    Log.Info("Could not find Device Database."); 
} 

一旦备份完成后,应用程序启动和第一连接的应用程序尝试与该.SDF所导致此异常:

There is a file sharing violation. A different process might be using the file. 

这里是日志文件的信息:

2013-05-13 11:52:29,894 [INFO ] - Starting database Verification. 
2013-05-13 11:52:33,832 [INFO ] - Database Verification successful. 
2013-05-13 11:52:33,838 [INFO ] - Database backup starting. 
2013-05-13 11:52:46,941 [INFO ] - Database backup complete. 
2013-05-13 11:52:47,933 [ERROR] - There is a file sharing violation. A different process might be using the file. [ \Program Files\ApplicationName\DB.sdf ] 
    at System.Data.SqlServerCe.SqlCeConnection.ProcessResults(Int32 hr) at System.Data.SqlServerCe.SqlCeConnection.Open(Boolean silent) 
    at System.Data.SqlServerCe.SqlCeConnection.Open() 
    at CFApp.MainScreen.GetStartupData() 
    at CFApp.MainScreen..ctor() 
    at CFApp.Program.RunInReleaseMode() 
    at CFApp.Program.Main() 

我一直在研究这个问题的原因星期了,我无法找到任何东西。任何指导或帮助将非常感激。

基于我的努力到目前为止,我可以证实这些东西

  • 问题发生随机。启动过程正确执行多次,然后它会随机抛出此错误
  • 考虑到应用程序刚刚处于启动过程中,此时没有其他连接正在对数据库进行。
  • 每次应用程序打开连接时,它会在完成后立即处理它。这是通过using声明完成的。如果意外关机/重新启动,没有打开的连接保持打开状态。
  • SqlCeEngine正在处理与using声明。物体被丢弃时到连接关闭时是否有延迟?
  • 目前没有其他进程在运行。该设备被锁定为仅允许我的应用程序被执行的 。经理 经理只显示ActiveSync和我的应用程序。该设备偶尔使用 OpenNETCF.Desktop.Communication通过USB与另一个桌面应用程序进行通信。有效 必须打开同步才能使其正常工作。它与之通信的台式计算机是Win XP。
  • 我在其他一些论坛上看到,ActiveSync可能会在文件上保留一个 锁,这可能会导致问题。在设备的ActiveSync 部分中,没有选择与 桌面同步。 “文件”复选框未选中。如果其他人对我如何确保从 ActiveSync中排除此文件有任何 建议,这也会非常有帮助。

  • UPDATE - 我用dotPeek来看看SqlCeEngine Dispose方法。我认为一切似乎都是为了这里,我的 连接应该妥善处理?

    private void Dispose(bool disposing) 
    { 
        if (!disposing) 
        return; 
        this.connStr = (string) null; 
        this.connTokens = (Hashtable) null; 
        NativeMethods.DllRelease(); 
        this.isDisposed = true; 
    } 
    
  • UPDATE - 我试图运行这个测试,看看我是否能重现错误,我想出了什么。代码正确执行并且应用程序开始运行,而不会发生任何文件共享问题。

    for (int i = 0; i < 50; i++) 
    { 
        using (SqlCeEngine engine = new SqlCeEngine(Resources.SqlCeConnectionString)) 
        { 
         //Log.Info("Starting database Verification."); 
         if (!engine.Verify()) 
         { 
          Log.Warn("Database failed verification."); 
          engine.Repair(null, RepairOption.RecoverAllOrFail); 
          Log.Info("Database successfully repaired."); 
         } 
         else 
         { 
          Log.Info("Verified" + i); 
         } 
        } 
    
        if (File.Exists(Resources.BackupDatabaseFileLocation)) 
        { 
         File.Delete(Resources.BackupDatabaseFileLocation); 
        } 
    
        File.Copy(Resources.DatabaseFileLocation, Resources.BackupDatabaseFileLocation); 
        Log.Info("File Copied " + i); 
        GetStartupData(); 
    } 
    

非常感谢您事先的任何信息可以提供。

+0

我只能假设数据库验证或备份还没有关闭文件。当您尝试访问数据库时,文件操作可能会缓存并仍在后台运行。对于file.write等我们有一个明确的Flush()方法,但我没有看到file.copy。如果将数据库访问权限(open)放在try catch块中,并在几次睡眠之间重试访问,会发生什么? – josef

+0

@josef明天我会尝试第一件事。我认为这是保持文件打开的方法之一,但我不知道哪一个。我知道SqlCeEngine打开一个FileMode = Exclusive的连接,如果有东西试图访问它,会导致错误,但是我立刻处理它,应该释放锁。我想知道File.Copy是否也会拥有独占锁定? – neverseenjack

回答

1

我发现并非所有的类都像他们应该的那样实现了IDisposable。例如,从using声明中调用时,Microsoft的OLE JET数据库引擎将不会关闭数据库连接。

您可能会在这里遇到这些问题。

作为开始,我建议您在连接上明确调用Close()。如果这不能解决问题,您可以添加一个明确的电话Dispose()

也可能是在应用程序尝试再次访问它之前,垃圾收集器(GC)没有机会处理所有IDisposable代码。

+0

我想到了这一点,但我发现了一些事情,导致我相信否则: – neverseenjack

+0

1. This post - http://social.msdn.microsoft.com/Forums/en-US/sqlce/thread/fef2a33a-d5a8 -46f8-84ed-cb334cb7647f 2. SqlCeEngine没有提供显式的“Close”方法。我用dotPeek来看看这个类,它的Dispose方法似乎正在清理资源。在using语句中调用Dispose()是多余的。 – neverseenjack

+0

...我看到它ActiveSync也不是一个嫌疑犯。您可以在设备进入和退出暂停模式时监听并处理吗?如果是这样,您可以尝试保持开放连接,直到设备进入挂起模式,关闭连接,然后在设备退出挂起模式时重新建立连接。 ...虽然,我个人不喜欢保持开放连接的想法。 – jp2code