﻿# 關於 Entity Framework 獨立放在 DAL 專案的注意事項

前幾天遇到幾個 Entity Framework 的連線問題，因此誓死研究出前因後果，本次研究頗有心得，雖然都是小東西，但應該算蠻重要的，對日後用 Entity Framework 開發 DAL 元件有很大的幫助。

注意: 以下專案範例都是以 **.NET 4.0** 為示範，使用 **.NET 3.5** 可能會有不同的結果。

**1\. 記得加入 System.Data.Entity 參考組件**

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/633c30e0c2f0efd5e616-image.png "image")

**2\. 在 ConsoleApp 使用 AdventureWorksLT.Model 專案的 EDMX 進行資料查詢**

使用連線參數最簡單的作法就是將 App.config 直接複製到 ConsoleApp 專案使用

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/dfe26b936ff916a6f58d-image.png)

如果已經有 App.config 或 Web.config 的話，只要將 ConnectionStrings 內的設定複製過去即可！

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3757d49a36cbc71af330-image.png)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/ddfeaa27dedd415ce45c-image.png)

若透過程式產生連線字串就有幾點需特別注意，首先在 DAL 專案中的 Entity Framework 連線參數如下：

> <add name="AdventureWorksLTEntities" connectionString="metadata=res://**\***/AdventureWorksLT.csdl | res://**\***/AdventureWorksLT.ssd l | res://**\***/AdventureWorksLT.msl; provider=System.Data.SqlClient; provider connection string=&quot;Data Source=.\\sqlexpress;Initial Catalog=AdventureWorksLT;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

上述連線參數最值得注意的地方是被標注紅色粗體的部分，在 **metadata** 屬性必須明確指出 **CSDL**、**SSDL** 與 **MSL** 三個檔案的位置，預設來說透過 Entity Framework 設計工具產生的 EDMX 檔的 \[**中繼資料成品處理**\] 屬性為 **內嵌在輸出組件中** (如下圖示)，所以當在 DAL 專案以外的地方要參考這三個檔案就必須修改 **metadata** 所指出的這三個檔案的路徑。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/4b285c3adcb2cfe03351-image.png)

若你的 **CSDL**、**SSDL** 與 **MSL** 三個檔案是設定內嵌在輸出組件中，你就必須在設定 Entity Framework 連線參數時將上述 **metadata** 標注 **\*** 的部分修改成組件名稱，這樣就能正確載入 Entity Framework 了，如下範例：

> metadata=res://**AdventureWorksLT.Model**/AdventureWorksLT.csdl | res://**AdventureWorksLT.Model**/AdventureWorksLT.ssd l | res://**AdventureWorksLT.Model**/AdventureWorksLT.msl; provider=System.Data.SqlClient; provider connection string=&quot;Data Source=.\\sqlexpress;Initial Catalog=AdventureWorksLT;Integrated Security=True;MultipleActiveResultSets=True&quot;

實際建立連線參數的程式碼可參考以下程式片段：

```csharp
static private string buildConnectString()
{
    SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
    builder.DataSource = @".\SQLEXPRESS";
    builder.ApplicationName = "";
    builder.InitialCatalog = "AdventureWorksLT";
    builder.IntegratedSecurity = true;
    builder.PersistSecurityInfo = true;

    EntityConnectionStringBuilder entBuilder = new EntityConnectionStringBuilder();
    entBuilder.Provider = "System.Data.SqlClient";
    entBuilder.ProviderConnectionString = builder.ConnectionString;
    entBuilder.Metadata = @"res://AdventureWorksLT.Model/AdventureWorksLT.csdl|res://AdventureWorksLT.Model/AdventureWorksLT.ssdl|res://AdventureWorksLT.Model/AdventureWorksLT.msl";

    return entBuilder.ConnectionString;
}
```

備註: 如果寫在 app.config 或 web.config 中是可以用 **\*** 符號替代，但如果發生異常就需要換成組件名稱。

如果你將 \[**中繼資料成品處理**\] 屬性設定為 \[**複製到輸出目錄**\]，就會在建置專案後將這三個檔案複製到預設輸出目錄：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/5e5596417ec54eb4a0cd-image.png)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/aa67b2af457029ba07d2-image.png)

你也可以將這三個檔案透過 Visual Studio 2010 \[**加入做為連結**\] 功能連結至要使用的專案：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/d8ed1516853b7d3cbde3-image.png)

[![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/54b322a22f300e2bb223-image_thumb.png)](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/173b444b2702bd5cd554-image.png)

加入連結後設定完成後，先選取這三個檔案，並按下 F4 開啟屬性視窗，並將 \[**複製到輸出目錄**\] 設定為 \[**有更新時才複製**\] 即可兩個專案共用同一組 Entity Framwork 產生的模型檔案：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/d64071a0b2845d5ee2f2-image.png)

專案編譯完成後的結果如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/b6ffbde4eb9f4d00a580-image.png)

最後一個步驟就是修改 **app.config** 的連線字串成如下 ( 請注意紅字部分組件所在目錄的相對路徑 )

> metadata=**.**/AdventureWorksLT.csdl | **.**/AdventureWorksLT.ssd l | **.**/AdventureWorksLT.msl; provider=System.Data.SqlClient; provider connection string=&quot;Data Source=.\\sqlexpress;Initial Catalog=AdventureWorksLT;Integrated Security=True;MultipleActiveResultSets=True&quot;

如果是 ASP.NET 環境下，就必須修改 **web.config** 中的連線參數如下 ( 請注意紅字部分相對於網站根目錄的 bin 目錄下，可使用 **~** 符號代表網站根目錄 )

> metadata=**~/bin**/AdventureWorksLT.csdl | **~/bin**/AdventureWorksLT.ssd l | **~/bin**/AdventureWorksLT.msl; provider=System.Data.SqlClient; provider connection string=&quot;Data Source=.\\sqlexpress;Initial Catalog=AdventureWorksLT;Integrated Security=True;MultipleActiveResultSets=True&quot;

若連線參數沒有設定好而導致 Entity Framework 無法讀取 **CSDL**、**SSDL** 與 **MSL** 三個檔案時，就會出現的 **Unable to load the specified metadata resource.** 或 **無法載入指定的中繼資料資源** 的錯誤。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0af2253a57905cc9b9a7-image.png)

範例程式下載：[AdventureWorksLT\_EF\_Sample.7z](http://cid-ce50199d9432ea57.office.live.com/self.aspx/%e5%85%ac%e9%96%8b/AdventureWorksLT%5E_EF%5E_Sample.7z)  ( 註: 請用 [7-Zip](http://7-zip.org/) 解壓縮 )

**相關連結**

-   [MetadataException: Unable to load the specified metadata resource](http://stackoverflow.com/questions/689355/metadataexception-unable-to-load-the-specified-metadata-resource)
-   [ADO.NET team blog](https://learn.microsoft.com/en-us/archive/blogs/adonet)
