2011-04-03 173 views
2

我正在研究在即將發佈的現有產品的項目中使用Microsoft實體框架。我們當前的產品支持兩個DBMS(Oracle和SQL Server),每個DBMS的架構都保存在單獨的.sql腳本文件中。實體框架 - 架構升級,多個DBMS和代碼優先

實體框架(4.1)看起來很吸引人,因爲它允許通過代碼生成,反射等自動實現各種場景。但是,據我所知,其中一些好處似乎與其他好處相互排斥。例如,爲了支持多個DMBS,我推斷我需要使用模型或代碼優先設計,在這種情況下,EF會根據模型爲每個模型生成模式(我已經很少看到任何帖子或關於此的文檔,所以我可能是錯的)。這意味着我們現有的模式需要被放棄(模型優先)或映射(先優先)。此外,更新模式需要手動腳本,因爲EF似乎不支持模式升級(不擦除數據)。

  1. 模型優先和代碼優先是在EF中支持多個DBMS的唯一可行方法嗎?我意識到,從技術上講,確保兩個任意模式是相同的是不可能的,所以我認爲這是事實。
  2. 是否存在代碼優先和映射到多個DBMS系統的潛在缺陷?例如,Oracle沒有自動增量列;你必須使用序列。這是如何映射到DbContext中的?我是否需要爲每個DBMS創建單獨的地圖?
  3. EF是否支持任何機制將現有的DBMS架構升級到其中一個代表EF模型(架構重建=/=升級),還是我僅限於手動執行此操作?
  4. 我確實想到了一種可能的方式來首先使用數據庫並支持多個DBMS,但這是一個維護噩夢。這個想法是爲兩個生成的數據模型添加另一個抽象層,併爲每個EF生成的模型創建轉換器類。這似乎是實現它的最佳方式,以便每個DBMS都可能擁有自己的模型,但我的代碼將處理映射。但是在這樣做的過程中,我真的從EF中獲得了什麼?也許查詢生成,但這是否值得?
+0

你考慮過看Nhibernate嗎? – 2011-04-03 06:19:43

+1

@Derek我曾考慮過查看Nhibernate,但是這與我關於EF的問題沒有直接關係。 – Travis 2011-04-03 23:45:32

回答

2

實際上,model-first和database-first都有相同的約束條件。這兩種方法都使用一個EDMX文件,該文件包含直接與單個數據庫提供程序相關的SSDL(store =數據庫層的描述)部分,因此如果您想要有兩個不同的數據庫提供程序,則必須有兩個不同的SSDL部分並保留它們同步。您可以使用單個CSDL(對概念層=您的模型類的描述)以及單個或兩個MSL(SSDL和CSDL之間映射的描述 - 只有在兩個SSDL中的表和列名稱具有完全相同的名稱時纔可以使用單個文件)。據我所知,EDMX文件只能由單個SSDL,CSDL和MSL部分組成,所以我期望設計師不支持這種情況,您將不得不手動修改第二個SSDL或使用兩個EDMX =模型每個更改兩次。

代碼優先的方法可以使這更簡單,但問題是Oracle提供程序在使用代碼優先和數據庫代時有多好。提供者負責在自動增量列的情況下正確解釋所需的功能,如序列。

EF本身目前不支持升級現有數據庫。使用EDMX時,數據庫生成過程由T4模板或Workflow控制,因此可以自定義,並且已經有一個名爲Entity Designer Database Generation Power Pack的獨立功能,可以使用模型優先方法增量構建數據庫。問題是這個功能使用VS數據庫工具。我認爲這些工具只適用於SQL服務器。我從來不喜歡這些自動化工具,因此我仍然認爲應該藉助一些工具手動控制數據庫升級,以獲得當前和最近部署的數據庫版本之間的差異腳本。只有在將新版本部署到生產環境時,您才需要差異腳本。在測試和開發環境中,您始終可以重新創建整個數據庫。

使用兩個EDMX模型時不需要抽象。模型必須產生相同的概念層。在這種情況下,您只需要一組按照慣例映射的POCO類(與實體具有相同的類名稱,具有相同類型和可訪問性的相同屬性),因此它們將與這兩種模型一起使用。

編輯:

基於@Tridus回答我只是補充說,你可以先創建數據庫,並使用fluentAPI從EF 4.1映射。你的數據庫必須有完全相同的模式(表名,列名等),它們不能使用任何特定的功能(我希望順序不會是問題,因爲它只是Oracle處理自動增量列的方式)。

+0

你能否詳細說明兩個EDMX模型如何產生相同的概念層?如果模型表示相同的模式/關係,我可以看到生成的類可能是相同的,但是生成的類仍然是明顯不同的文件(雖然可能具有相同的屬性)。 – Travis 2011-04-03 23:43:13

+0

另外,你可以詳細說明如何擁有一組具有兩個映射的模型類嗎?我知道如何用代碼先做(重寫OnModelCreating),但如何用數據庫或模型優先設計來做到這一點? – Travis 2011-04-03 23:54:44

1

這實際上對於數據庫的第一個設計來說是相當可行的,但是由於數據庫處理事物的方式不同,因此您將無法輕鬆解決這些問題。

  • 序列是一個(因爲它們完全被EF忽略)。你可以在Oracle中通過在填充Insert的表上放置一個觸發器來僞造它,但是我還發現,如果以後必須更新模型,那麼EF「忘記」該列是標識列,它會嘗試再次粘貼0。如果您使用觸發器,我還發現在Oracle中嘗試獲取新ID是不可靠的。在完成插入之前,我們只是從序列中選擇並設置對象的ID,因爲這就是您通常在Oracle中執行的方式。您也可以使用處理它的存儲過程。

  • 數字處理方式不一樣。 SQL Server使用映射到Int32,Int64等的數字格式.Oracle的數字格式完全不同,SQL Server中的全範圍Int32是Oracle中的Number(10,0)...實際上是EF中的Int64,因爲它是比Int32大一些。我還發現,Oracle的EF提供程序甚至在不需要時也喜歡使用Decimal,但這可能只是一個測試版問題。

  • Oracle中的存儲過程需要將一些值放在app.config/web.config中才能在EF中工作。我不確定這是否會在SQL Server中變得混亂,或者它會導致問題。

最後,EF Code First相當不成熟,根據文檔不支持在此版本中更改數據庫結構。我不確定Oracle的提供者是否支持它(它可能沒有嘗試過)。

大部分情況是你可以解決的問題,但是你需要做一些工作來隱藏與代碼其餘部分的不同之處,它可能需要一個包裝層才能完成。

編輯 - 關於您的#4 - EF 4.1可以生成部分POCO類。您不必爲每個生成的模型編寫包裝以隱藏任何差異,而是可以創建另一個部分類代碼文件,在更新模型時不會重新生成該代碼文件,然後添加隱藏差異的屬性/方法。你的應用程序代碼只需要知道使用這些代碼,他們會處理這個問題(就像我提到的數字問題,你可以用另一個可以爲Oracle進行必要的投射的屬性完全隱藏它)。

+0

我需要使用Oracle EF提供程序(目前處於測試階段)來查看它如何處理序列。關於你的編輯,這聽起來像你建議有兩套生成的POCO部分類,這兩個部分類都可以用一組其他類來擴展?如果兩組POCO對象位於不同的命名空間中,我將如何執行此操作? – Travis 2011-04-03 23:46:55

+0

我的意思是讓Oracle EF提供程序生成與您的SQL Server POCO位於相同名稱空間的POCO(不同於您的模型和DbContext的位置)。您可以在項目中將它們交換出來,具體取決於您要使用的數據庫,並且代碼不會知道其差異。在Oracle項目中,您可以爲任何現有的POCO添加部分類文件,以添加使其與SQL Server版本保持一致的屬性,並更有效地隱藏任何差異。 – Tridus 2011-04-04 00:19:24

+0

我開始傾向於以下之一 - 1:廢棄現有的SQL腳本並使用POCO在代碼中重新創建整個模型。要升級產品的現有版本,請編寫一個執行升級的SQL腳本。或2:重新創建代表現有模式的POCO,並手動將它們映射到DbContext.OnModelCreating() - 一個用於SQL和Oracle。我將在單獨的問題中發佈這些信息以徵求反饋意見。 – Travis 2011-04-04 04:41:10