woggles
woggles

Reputation: 7444

Delete a file from database and file system

I have a table that references files in a shared location on our network (stores the file path in the database).

I have a button that needs to delete the record from the database and the file off the File System:

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

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

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

An exception could be thrown when deleting the file or deleting the database record and if this happens I would like neither of the operations to complete.

Is there an easy way to ensure both operations are carried out successfully?

Upvotes: 16

Views: 4829

Answers (5)

Claudio Redi
Claudio Redi

Reputation: 68440

You have to do 2 two things

  • Wrap the whole process inside a database transaction.

  • Delete file from database before doing it from file system

If the process fails deleting from database, physical file won't be removed as you haven't reached file system delete logic.

If the process fails deleting from file system you rollback transaction and database operation is reverted.

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();
    }
}        


While I believe this is the safer approach you can implement wihout getting really complex I agree that there is no synchronous approach that guarantee 100% of efficacy. To be sure that no orphan item remains, you'll have to implement a background clean up process. You'll have to analyze if such an extra complexity is justified or not according your scenario.

Upvotes: 24

Tim B
Tim B

Reputation: 2368

.NET Transactional File Manager looks like it could be useful for what you are trying to do. The examples seem to indicate that you can tie a database operation and a file operation together into a single transaction. I have never used it, so I can't say for certain.

Edit: I looked at the source code, and this library does nothing special. For a delete transaction, it just does a copy, then delete, like some others have suggested here.

Upvotes: 0

L-Four
L-Four

Reputation: 13541

Delete the file from database and file system in a transaction:

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
   }       
}

If the deletion of the file on a physical drive fails for some reason, the database deletion will be rolled back too.

If the deletion in the database failed, the file won't be deleted physically.

Commit is only executed if both physical delete and database delete has succeeeded.

So whatever exception might occur; you end up in a consistent state.

Upvotes: 3

David Scott
David Scott

Reputation: 1084

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);
}

Instead of using .txt you can also use the FileInfo to get filePath extension if they will all be different, or Split on '.' and take split[1] value and append to the end of copyPath. Up to you

Upvotes: 1

Vijay Hulmani
Vijay Hulmani

Reputation: 989

The solution would be
1) Copy the file to other temp location and then delete.
2) On successful deletion,then delete the record from the DB.
3) If some exception thrown from the DB,copy back the file and delete the file from temp location.
4) If evrything is successful ,then clear the file from temp location.

Upvotes: -1

Related Questions