Entity Framework Model First下改變資料庫指令碼的生成方式

dax.net發表於2014-02-09

在Entity Framework Model First下, 一個非常常見的需求是改變資料庫指令碼的生成方式。這個應用場景是指,當使用者在Designer上單擊滑鼠右鍵,然後選擇Generate Database from Model選項,此時Entity Framework Model First會根據模型產生資料庫SQL指令碼,並將SQL指令碼檔案新增到解決方案資源管理器中。

事實上,這個自動化產生的資料庫SQL指令碼還是會有一些侷限性。比如:Model上支援DateTime這一CLR型別,在自動化SQL生成的過程中,Entity Framework會自動使用SQL中的資料型別datetime來產生相應的欄位定義,如果我們希望對於某些DateTime型別的屬性產生date型別,而不是datetime型別的欄位,那麼我們就需要對資料庫指令碼的生成方式做一些修改。

例子

首先看一個例子,我們建立一個非常簡單的模型:Employee,在這個Employee實體中會有一個DayOfBirth的屬性,用以儲存僱員的生日日期。該模型定義如下:

SNAGHTML7bcee4

在模型設計器上單擊滑鼠右鍵,選擇“Generate Database from Model”選單後,產生的SQL語句如下,可以看到,對於DayOfBirth屬性,產生的欄位是datetime型別:

image

現在,讓我們來嘗試改變Entity Framework Model First下資料庫SQL指令碼的生成方式,以使得所產生的DayOfBirth欄位為date型別。

實現

通過使用Entity Framework的Structural Annotation的特性,我們可以很方便地定製SQL指令碼的生成方式。

首先,在Solution Explorer中,找到模型檔案(副檔名為edmx的檔案),單擊滑鼠右鍵,選擇Open With選項。在Open With對話方塊中,選擇Automatic Editor Selector:

SNAGHTML522dd4

此時會關閉模型設計器,並以XML編輯器的方式開啟edmx檔案。在開啟的編輯器中,我們可以看到edmx檔案的詳細內容。如果模型比較大的話,這個檔案的內容也會比較多(有的甚至幾千幾萬行)。總體來看,主要有三個部分:

image

  • SSDL content:對儲存模型的定義
  • CSDL content:對概念模型的定義 - 也就是儲存設計器上所設計的模型
  • C-S mapping content:定義了概念模型與儲存模型之間的對映

一看就知道,Entity Framework就是一個ORM框架(廢話)。

接下來,我們要對edmx的概念模型部分做一些修改。修改的目的就是為了給SQL指令碼的自動化生成提供一些客戶化的資訊,以便自動化生成工具能夠根據這些客戶化資訊產生不同的結果。

我們需要在ConceptualModels節點下的Schema上定義自己的名稱空間。例如:

image

然後,我們自己自定義一個XML標籤,並把這個標籤應用到概念模型中的DayOfBirth屬性上,如下:

image

注意此處的“edmx:CopyToSSDL”屬性,意思是這部分屬性需要在產生模型的時候複製到SSDL儲存模型中。因為在生成SQL指令碼時,轉換引擎會讀取SSDL中的內容並根據這些內容產生SQL。現在,我們雙擊edmx檔案,並重新在設計器中開啟模型。同樣在設計器中點選滑鼠右鍵,選擇“Generate Database from Model”選項,待SQL指令碼重新生成之後,再用XML編輯器開啟edmx檔案,此時我們會看到,在SSDL部分,先前新增的“custom:SqlType”節點也被複制到了這裡,只不過稍許有些變化:

image

現在,我們需要定製SQL指令碼的產生過程。開啟模型設計器,在模型設計器的屬性編輯視窗中,我們可以看到一個名為“DDL Generation Template”的屬性:

SNAGHTML1b224f

它就是主導SQL指令碼生成的T4模板檔案,現在需要對這個T4檔案進行定製。該檔案位於%PROGRAMFILES(x86)%\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen目錄下。為了不更改原有的SSDLToSQL10.tt檔案,我們將其複製到Solution Explorer中,注意將該檔案的BuildAction設定為None,並去掉Custom Tool的設定:

image

仍然開啟模型設計器,在屬性視窗中,設定“DDL Generation Template”屬性為“.\SSDLToSQL10.tt”,注意路徑符“.\”,它表示需要使用Solution Explorer下的SSDLToSQL10.tt檔案,而不是標準的那個檔案。

最關鍵的一步,就是修改SSDLToSQL10.tt檔案。開啟這個檔案,找到“Creating all tables”部分,並用以下粉紅色高亮部分替換其中的內容:

image

注意:我們還需要在這個tt檔案的頂部引入System.XML和System.XML.Linq的名稱空間:

<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>

至此,實現部分已經完成。

測試

現在來測試一下效果。雙擊開啟edmx模型,在模型設計器上單擊滑鼠右鍵,選擇“Generate Database from Model”,然後檢視生成的SQL語句。我們發現,DayOfBirth已經變成了date型別了:

image

如果在產生資料庫指令碼的時候提示以下錯誤,請稍許更改一下模型(比如拖動一下模型中的實體等)儲存之後再試。

image

相關文章