﻿# 解決 Entity Framework 6 無法在交易內進行備份或還原動作的問題

我們都知道 Entity Framework 是一個 [ORM](http://zh.wikipedia.org/zh-tw/%E5%AF%B9%E8%B1%A1%E5%85%B3%E7%B3%BB%E6%98%A0%E5%B0%84) 框架，在應用程式中基本上都不太會去碰觸太多關於後端資料庫的特定語法，但針對一些效能調校或資料庫管理等需求時，其實還是能透過 Entity Framework 幫我們執行一些自訂的 T-SQL 語法，只是有些地方需要注意一下，如果你今天遇到無法在 Entity Framework 中執行預存程序或匯入函式時，那麼這篇文章可能對你有幫助。

如果要在 Entity Framework 中執行任意 DDL 命令，可以使用 DbContext 類別下的 [Database](https://msdn.microsoft.com/en-us/library/system.data.entity.database\(v=vs.113\).aspx) 屬性來執行任意命令，主要有以下方法可用：

-   [ExecuteSqlCommand(String, Object\[\])](https://msdn.microsoft.com/en-us/library/gg679456\(v=vs.113\).aspx)
-   [ExecuteSqlCommand(TransactionalBehavior, String, Object\[\])](https://msdn.microsoft.com/en-us/library/dn220053\(v=vs.113\).aspx)  \[ 這個方法 EF6 才提供 \]

底下有個簡單的例子可以重現本文想強調的問題，以下是透過 [ExecuteSqlCommand](https://msdn.microsoft.com/en-us/library/gg679456\(v=vs.113\).aspx) 執行一段「備份資料庫」的 T-SQL 命令，照理說 Entity Framework 會原封不動的將 T-SQL 送到 SQL Server 執行：

```
using (var db = new ContosoUniversity2Entities()){    db.Database.ExecuteSqlCommand("BACKUP DATABASE [ContosoUniversity2] TO  DISK = N'G:\\ContosoUniversity2.bak' WITH NOFORMAT, NOINIT,  NAME = N'ContosoUniversity2-Full Database Backup', SKIP, NOREWIND, NOUNLOAD");}
```

這段程式碼如果跑在 **Entity Framework 5** (**EF5**) 的話，其實是沒有問題的！

不過，如果你的專案用的是 **Entity Framework 6** (**EF6**) 時，此時你就會得到 [System.Data.SqlClient.SqlException](https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception%28v=vs.110%29.aspx) 的例外錯誤，中英文錯誤訊息如下：

-   Cannot perform a backup or restore operation within a transaction.
-   無法在交易內進行備份或還原動作。

會得到這句錯誤訊息的原因是，EF6 當透過 **預存程序** (Stored Procedure) 或 **ExecuteSqlCommand** 來執行一些特殊的 DDL 命令時，因為 Entity Framework 6 預設會自動啟用**交易處裡**，這會導致那些「**不能啟用交易時執行的 T-SQL 命令**」無法被執行，例如 備份(Backup)、還原(Restore) 或 修改(Alter) 資料庫等工作。

從 Entity Framework 6.1.2 開始，在 db.Configuration 屬性下增加了一個新屬性，叫做：

-   [EnsureTransactionsForFunctionsAndCommands](https://msdn.microsoft.com/de-de/library/system.data.entity.core.objects.objectcontextoptions.ensuretransactionsforfunctionsandcommands\(v=vs.113\).aspx)

這個屬性值預設為 **true**，也就是所有執行 EF 匯入函式或自訂命令時，會自動啟用交易處理。

因此，如果要執行特殊命令時，只要將他修改成 false 就可以順利執行了，範例程式如下：

```
using (var db = new ContosoUniversity2Entities()){    db.Configuration.EnsureTransactionsForFunctionsAndCommands = false;    db.Database.ExecuteSqlCommand("BACKUP DATABASE [ContosoUniversity2] TO  DISK = N'G:\\ContosoUniversity2.bak' WITH NOFORMAT, NOINIT,  NAME = N'ContosoUniversity2-Full Database Backup', SKIP, NOREWIND, NOUNLOAD");}
```

  
最後一點請注意，設定這個 [EnsureTransactionsForFunctionsAndCommands](https://msdn.microsoft.com/de-de/library/system.data.entity.core.objects.objectcontextoptions.ensuretransactionsforfunctionsandcommands\(v=vs.113\).aspx) 屬性不會影響 [SaveChanges()](https://msdn.microsoft.com/en-us/library/dn219930\(v=vs.113\).aspx) 的任何動作或行為模式。  
  

**相關連結**

-   [ObjectContextOptions.EnsureTransactionsForFunctionsAndCommands Property (System.Data.Entity.Core.Objects)](https://msdn.microsoft.com/en-us/library/system.data.entity.core.objects.objectcontextoptions.ensuretransactionsforfunctionsandcommands\(v=vs.113\).aspx)
-   [Entity Framework - View Issue #1612: Allow disabling transactions for function imports](https://web.archive.org/web/20160912233619/https://entityframework.codeplex.com/workitem/1612)
-   [Entity Framework - unable to backup using EF](https://web.archive.org/web/20160710141007/http://entityframework.codeplex.com:80/discussions/454994)
