Entity Framework的存儲模型切換實踐
【本文選自微軟MVP林立的博客】最近做一個項目,里面需要同時支持SQL Server和SQLite。考慮到Entity Framework雖然目前還有諸多不足,但是基本上滿足于我的項目的要求,加上,也希望做一個嘗試,畢竟,雖然使用過去的技術和手段可能更可靠、更熟練、風險更低。
作者簡介:
林立,微軟ASP.NET與C# MVP,專注和熱衷于將.NET平臺下較為成熟的新技術實踐于實際項目開發,近期著重于研究Entity Framework和Windows Workflow Foundation。
但是,在技術行業,不能止步不前,如果某種新技術有你需要的某些特性,并且你認為值得嘗試,那就應該出手試試,雖然嘗試可能會失敗(以及不得不吞下失敗產生的苦果),但是如果成功,其帶來的好處也是很大的,也代表著你又往前邁進了一步。對于Entity Framework我也是新手,如果各位朋友發現文中有什么可以改進的地方或者不正確的地方,歡迎指點。
廢話不多說了,切入正題。Entity Framework需要三種文件支持:CSDL(概念架構定義語言)、SSDL(存儲架構定義語言)、MSL(映射規范語言),以及,一個據此生成的類文件(這里我們不研究這個類文件)。從這種結構上看,EF是完全支持上層穩定的概念架構與底層具體可變動的存儲架構之間的獨立和分離的。但通常我們利用VS的設計器只能生成一個單獨的.edmx文件,其中包含了CSDL、SSDL和MSL的內容,而本質上,它們3個是完全可以獨立成3個文件的。對于我們當前的目標,我們需要把SSDL從.edmx文件中剝離出來,并創立分別針對于SQL Server和SQLite的SSDL,下面詳述一下我的做法。
1、根據SQL Server中的表、視圖結構,創建SQLite數據庫
由于之前已經SQL Server上已經有了相關的表和視圖,因此以Sql Server為模板,創建SQLite數據庫,并在SQLite數據庫中創建與SQL Server中的表和視圖幾乎完全一樣的表和視圖。之所以說“幾乎完全一樣”,是因為SQLite中的類型系統與SQL Server中的差別很大。但是因為我沒有用到SQL Server中太特別的類型,因此這個問題的解決相對容易一些。我從SQL Server中生成表和視圖的腳本,然后修改一下讓SQLite可以識別和執行。
主要的修改包括,去掉“dbo”架構的指定,將自增標識列主鍵的聲明“int identity(1,1) primary key”改為“integer primary key autoincrement”,后者是SQLite中自增列主鍵的聲明語句,對于其他簡單類型,比如varchar/nvarchar, bit, money等等類型則保留原有的聲明不變,這些類型雖然SQLite并不“支持”,但是執行的時候并不會出錯,而且利用“.schema”命令查詢表架構時,這些類型的聲明是被保留的(后面在生成針對SQLite的EDM的時候,似乎也說明這些類型聲明產生了正面作用),另外,有一點,這次我沒有用到DateTime類型,因此無法斷定2種數據庫對它的支持的差別。SQLite的類型系統的特點是,動態性,雖然你創建表的時候可以指定某種“類型”,但是你完全可以向一個“int”列插入一個字符串。最后,我沒有在SQLite中創建任何外鍵約束,雖然SQLite支持外鍵,但是為了簡化復雜性(畢竟這是我的初次嘗試),就犧牲一些“完整性”吧。由于保證了SQLite中的表和視圖與Sql Server中的完全一致(除了類型上的固有差別),因此,可以保證兩者在創建EDM的時候,其CSDL和MSL是完全相同的。
2、依據SQL Server創建EDM
具體方法就和我們平常做的一樣。利用VS比較強大的設計器,從SQL Server中生成模型,并且創建好各個實體之間的Association。經過這一步,我們會得到一個.EDMX文件以及一個對應的類文件。
3、創建針對SQL Server的SSDL文件
用XML編輯器打開上面生成的.EDMX文件,可以很清楚的分辨出SSDL、CSDL、MSL三部分。我們把“<edmx:StorageModels>”節點下的<Schema>節點的所有內容Copy出來,然后新建一個后綴名為.SSDL的XML文件,把Copy出來的Schema元素粘貼進去,保存,就可以了。
4、創建針對SQLite的SSDL文件
這一步有2種辦法:將針對SQL Server的SSDL文件復制一份過來,然后將其修改成符合SQLite的要求。主要是去掉一些SQLite不支持的東西,比如,對于Schema="dbo"這樣的聲明。以及,修改Schema元素的Provider屬性和ProviderManifestToken屬性。前者需要修改為"System.Data.SQLite",后者修改為“ISO8601”(為何改成這2個值?看到后面就會知道了)利用VS的設計器重新針對SQLite數據庫生成一份EDMX文件,然后抽取其中的SSDL定義。
我采用的是第二種方法:這里需要用到針對SQLite的ADO.NET提供程序,即System.Data.SQLite。這個東西真正的下載地址在http://sourceforge.net/projects/sqlite-dotnet2/files/。
下載完成之后,可以安裝,然后就可以在項目中引用System.Data.SQLite并利用設計器創建針對SQLite數據庫的EDM。創建和提取SSDL的內容與針對SQL Server的完全一樣,不再贅述,由此,我們可以得到一個針對SQLite的SSDL文件,其中Schema元素的Provider屬性值是System.Data.SQLite,而ProviderManifestToken屬性是ISO8601。
這里還需要指出的一點是,后來在測試的時候,發現運行失敗,原因是,在SSDL中存在不同的表/實體類型中引用和被引用的字段(外鍵字段)Type屬性不一致的情況,比如假設Company類型的CompanyID字段在Company類型中的type是integer,但是在引用它的Employee類型中的CompanyID字段的type是int,在這里,比如把它們2個統一為int或integer才可以。
5、通過修改連接字符串來切換不同的SSDL
在我的項目中,我將這2個SSDL分別作為2個不同的程序集的資源內嵌到程序集中。然后通過修改連接字符串來切換到某個SSDL。連接字符串看起來是這樣的:
- metadata=res://GE/GTDP.GTDEDM.csdl|res://LiteTDP/LiteTDP.GTDEDM.ssdl|res://GE/GTDP.GTDEDM.msl;
- provider=System.Data.SQLite;
- provider connection string="
- Data Source=D:\Practice\SQLite\Ricky.db;"。
注意連接字符串中對于CSDL、SSDL、MSL的指定,都指定到具體程序集的相關資源,其中黃色底色部分指定了使用SQLite的SSDL,而CSDL和MSL則直接使用了第二步中生成的EDMX中的內容。
補充:
在第二步中生成的EDMX被完整的保留下來,這樣,仍然可以隨時利用設計器打開和操作。而針對SQLite生成的EDMX在提取需要的SSDL之后被我刪掉了。當然了,是留是刪,完全看需要,很久沒有寫東西,都不會說話了,如果讀起來別扭,請多包涵了。
本文轉載自零度的火的博客,
原文地址:http://www.cnblogs.com/Ricky81317/archive/2010/02/22/1670867.html
【編輯推薦】
- 關系數據庫的根本問題分析及數據庫革命之走向
- 探尋關系數據庫和ORM的最佳替代者
- 數據庫機時代將到來 DBA面臨新挑戰
- 分布式緩存系統Memcached入門指導
- 扔掉沉沒成本 嘗試關系數據庫替代品OODBMS
【責任編輯:王曉東 TEL:(010)68476606】