13

我有一个表,它引用了我们网络上共享位置的文件(将文件路径存储在数据库中)。

我有一个按钮需要从数据库中删除记录和文件系统中的文件:

foreach (var report in reports)
{
      string filePath = report.ReportPath;

      if (File.Exists(filePath));
      {
         File.Delete(filePath);
      }                      

      context.ReportGenerations.DeleteObject(report);
      context.SaveChanges();
}

删除文件或删除数据库记录时可能会引发异常,如果发生这种情况,我不希望完成任何操作。

有没有一种简单的方法可以确保两个操作都成功执行?

4

5 回答 5

21

你必须做两件事

  • 将整个过程包装在数据库事务中。

  • 在从文件系统中删除文件之前从数据库中删除文件

如果进程从数据库中删除失败,则不会删除物理文件,因为您尚未达到文件系统删除逻辑。

如果该过程无法从文件系统中删除,则您回滚事务并恢复数据库操作。

DbTransaction transaction = null;
foreach (var report in reports)
{
    try
    {
        transaction = context.Connection.BeginTransaction();

        context.ReportGenerations.DeleteObject(report);
        context.SaveChanges();

        string filePath = report.ReportPath;
        if (File.Exists(filePath));
        {
            File.Delete(filePath);
        }
        transaction.Commit();
    }
    catch
    {
        transaction.Rollback();
    }
}        


虽然我相信这是您可以在不变得非常复杂的情况下实施的更安全的方法,但我同意没有同步方法可以保证 100% 的功效。为确保不存在任何孤立项目,您必须实施后台清理过程。您必须根据您的情况分析这种额外的复杂性是否合理。

于 2013-06-20T12:49:48.853 回答
3

在事务中从数据库和文件系统中删除文件:

using (TransactionScope scope = new TransactionScope(TransactionScope.Required, 
 new TransactionOptions 
     { IsolationLevel = IsolationLEvel.ReadCommitted}))
{
   try 
   {
       // Delete file from database
       // Delete physical file 
       // commit
   }
   catch (Exception ex)
   {
       // no commit, so database deletion will be rolled back
   }       
}

如果物理驱动器上的文件删除由于某种原因失败,数据库删除也将被回滚。

如果数据库中的删除失败,文件将不会被物理删除。

仅当物理删除和数据库删除都成功时才会执行提交。

所以无论发生什么异常;你最终处于一致的状态。

于 2013-06-20T12:52:12.893 回答
1
foreach (var report in reports)
{
      string filePath = report.ReportPath;
      string copyPath = @"C:\temp\tempFile.txt"
      try
      {
           if (File.Exists(filePath));
           {
              File.Copy(filePath, copyPath);
              File.Delete(filePath);
           }                      

           context.ReportGenerations.DeleteObject(report);
           context.SaveChanges();               
      }
      catch(Exception ex)
      {
           File.Copy(copyPath, filePath);
      }
      File.Delete(copyPath);
}

除了使用 .txt 之外,您还可以使用 FileInfo 来获取 filePath 扩展名(如果它们都不同),或者在“。”上拆分 并获取 split[1] 值并附加到 copyPath 的末尾。由你决定

于 2013-06-20T12:57:39.437 回答
0

.NET 事务文件管理器看起来对您尝试做的事情很有用。这些示例似乎表明您可以将数据库操作和文件操作绑定到一个事务中。我没用过,所以不能肯定。

编辑:我查看了源代码,这个库没有什么特别之处。对于删除事务,它只是复制,然后删除,就像其他人在这里建议的那样。

于 2013-06-20T17:14:39.143 回答
-1

解决方案是
1) 将文件复制到其他临时位置,然后删除。
2)成功删除后,从数据库中删除记录。
3)如果从数据库中抛出一些异常,复制回文件并从临时位置删除文件。
4)如果一切成功,则从临时位置清除文件。

于 2013-06-20T12:56:18.430 回答