讓Entity framework支持多數據庫
羅朝輝 (http://kesalin.cnblogs.com/)
EF對Sql Server的支持非常好,無論是Code First,還是 Model First 還是 Database First 都支持的很好,但是對非微軟系數據庫的支持就不那么友好了,現在唯一能保證的是對大部分數據庫的 Database First 支持的很好。所以在這里,我們讓 Entity framework 支持多數據庫實現的思路就是基於 Database First 的。首先在各數據庫中創建好數據庫表(這里有很多講究的地府,字段類型必須一致,可以使用Power Designer工具來簡化手工勞動),再基於某一數據庫生成概念模型,存儲模型以及映射關系,然后拷貝生成的存儲模型文件並修改,使之能與其他數據庫匹配起來,從而獲得對多數據庫的支持。
本示例演示了對Sql Server 2008和MySQL 5.5兩種書庫的支持,使用的 MySQL Connector Net 6.3.5。請參考前文安裝相關的軟件。下面講述具體步驟:
1,分別在 Sql Server 2008 和 MySQL 5.5 建立數據庫 school及表 student(推薦使用小寫,MySQL默認使用小寫),student表只包含三個字段:Id(主鍵),Name 和 Age。請注意兩個表的數據類型必須完全一致!
Sql Server 2008表:
MySql 表:
2,然后分別在兩個表中插入不同的測試數據,也可以在代碼中寫插入數據,這里為了簡化,直接使用數據庫管理工具插入測試數據。
3,新建C#控制台程序 EFMutilpleDatabase:
4,右擊項目名,向其中添加類型為ADO.NET Entity Data Model的新Item:StudentModel.edmx:
選擇從數據庫產生:
然后新建 Connection,首先我們使用 MySQL數據庫,設置連接到MySQL的Connection,數據庫表選擇 school,這樣向導就會自動為我們生成概念模型,存儲模型以及映射關系,connection string等:
選擇需要用到的數據庫表:
5,至此向導工作完成,我們先來看看向導為我們生成的文件:
App.Config:數據庫連接相關的配置;
StudentModel.edmx:概念模型,存儲模型,映射關系等都自動生成在該文件中;
StudentModel.Designer.cs:自動生成的代碼,通過這些自動生成的數據對象類,我們就可以直接操作數據庫。
6,為了方便后面支持多數據庫,我們現在在App.Config文件中修改默認 connection string的名字為:schoolEntitiesMySQL。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="schoolEntitiesMySQL" connectionString="metadata=res://*/StudentModel.csdl|res://*/StudentModel.ssdl|res://*/StudentModel.msl;provider=MySql.Data.MySqlClient;provider connection string="server=localhost;User Id=root;password=yourpwd;Persist Security Info=True;database=school"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
7,下面我們來編寫測試與MySQL的連接的代碼。相工程中添加 reference:System.Configuration,然后修改 Program.cs為:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects;
using System.Configuration;
namespace EFMultipleDatabase
{
class Program
{
private static void ProcessDatabase(string connectionStringName)
{
string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
using (var queryContext = new schoolEntities(connectionString))
{
Console.WriteLine(">> All Student:");
queryContext.Connection.Open();
// Query
//
using (var transaction = queryContext.Connection.BeginTransaction())
{
var people = from p in queryContext.student orderby p.Age select p;
foreach (var p in people)
{
Console.WriteLine(" {0}, Age: {1}", p.Name, p.Age);
}
transaction.Commit();
}
queryContext.Dispose();
}
}
static void Main(string[] args)
{
Console.WriteLine(" ========MySQL=====");
ProcessDatabase("schoolEntitiesMySQL");
Console.ReadLine();
}
}
}
在上面的代碼中,我們是根據讀取 App.Config 中的 connection string 配置來決定連接到哪一個數據庫的,這樣的設計方便我們添加與其他數據庫連接配置,以支持多種數據庫。
8,下面我們來讓程序支持 Sql Server 2008。首先,需要手動創建存儲模型文件,在項目中新建名為StudentModel.SqlServer.ssdl 的xml文件。然后右擊StudentModel.edmx選擇 Open With XML(Text) Editor,將<!-- SSDL content -->之后介於 <edmx:StorageModels> … </edmx:StorageModels>之間的內容拷貝至新建的StudentModel.SqlServer.ssdl文件中,這樣StudentModel.SqlServer.ssdl的內容應該如下:
<?xml version="1.0" encoding="utf-8" ?>
<Schema Namespace="schoolModel.Store" Alias="Self" Provider="MySql.Data.MySqlClient" ProviderManifestToken="5.1" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
<EntityContainer Name="schoolModelStoreContainer">
<EntitySet Name="student" EntityType="schoolModel.Store.student" store:Type="Tables" Schema="school" />
</EntityContainer>
<EntityType Name="student">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="Name" Type="varchar" MaxLength="45" />
<Property Name="Age" Type="umediumint" />
</EntityType>
</Schema>
9,緊接着我們來修改 StudentModel.SqlServer.ssdl 存儲模型文件,使之能與匹配Sql Server 2008數據庫表。首先我們需要將 Provider 和 ProviderManifestToken修改為:
Provider="System.Data.SqlClient" ProviderManifestToken="2008"
這表示該存儲模型是基於 Sql Server 2008 數據庫的。然后將各個字段的 Type 修改為Sql Server 2008支持的數據類型(MySQL使用的數據類型肯定不會與Sql Server 2008完全相同),並將該存儲模型放到輸出目錄下,修改該文件的屬性 Copy to Output Directory 為 Copy Always。。修改之后的內容應如下:
<?xml version="1.0" encoding="utf-8" ?>
<Schema Namespace="schoolModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
<EntityContainer Name="schoolModelStoreContainer">
<EntitySet Name="student" EntityType="schoolModel.Store.student" store:Type="Tables" Schema="dbo" />
</EntityContainer>
<EntityType Name="student">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" Nullable="false"/>
<Property Name="Name" Type="nchar" MaxLength="45" />
<Property Name="Age" Type="int" />
</EntityType>
</Schema>
10,這樣我們就完成了對存儲模型的修改,下面我們來在App.config中增加對Sql Server 2008數據庫的連接 string。以下是修改之后的App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="schoolEntitiesMySQL" connectionString="metadata=res://*/StudentModel.csdl|res://*/StudentModel.ssdl|res://*/StudentModel.msl;provider=MySql.Data.MySqlClient;provider connection string="server=localhost;User Id=root;password=yourpwd;Persist Security Info=True;database=school"" providerName="System.Data.EntityClient" />
<add name="schoolEntitiesSqlServer" connectionString="metadata=res://*/StudentModel.csdl|StudentModel.SqlServer.ssdl|res://*/StudentModel.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=school;persist security info=True;user id=sa;password=
yourpwd
;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
11,至此配置工作完成,我們只需在 main()中調用如下語句即可測試與Sql Server 2008數據庫的連接:
static void Main(string[] args)
{
Console.WriteLine(" ========MySQL=====");
ProcessDatabase("schoolEntitiesMySQL");
Console.WriteLine(" ========SQL Server 2008=====");
ProcessDatabase("schoolEntitiesSqlServer");
Console.ReadLine();
}
編譯運行,結果如下:
總結:
上面的過程是先生成一致的數據庫表,然后通過某種數據庫生成概念模型,存儲模型以及映射關系,然后拷貝並修改存儲模型,使之與其他數據庫匹配,從而完成對多數據庫的支持。