接觸ADO.NET Entityframework有一段時間了,在實際項目的應用中有一個最大的問題就是M$沒有對多種數據庫提供支持,在筆者最近碰到的一個網站項目中,公司要求使用MYSQL,到處找MYSQL的EFProvider,發現Devart dotConnect還不錯,提供了比較完善的解決方案,只是在自動從數據庫提取物理模型中存在編碼的問題,到目前還沒有找到解決辦法,但是Devart dotConnect是收費的,專業版得上千美刀,有Free Edition,但是不提供對EntityFramwork的支持。無奈,尋找其他的解決方案。
偶然間在一份SUN的文檔中有提到在未來版本中對AEF的支持,到MYSQL.com下載最新的MySql.Data.dll為5.2.5版,並沒有對AEF提供支持,再到源碼服務器,驚喜得看到多了一個MySql.Data.Entity項目,MySql.Data也已經到了5.3.0版。立刻下載。
下載後先編譯MySQL.Data,並簽名程序集,MySQL.Data.Entity引用MySQL.Data,編譯並簽名,取得MySQL.Data.Entity的PublicKeyToken,修改MySQL.Data中類MySqlClientFactory的IServiceProvider.GetService方法相關的代碼,將Provider類型指向剛才編譯好的MySQL.Data.Entity程序集中的MySql.Data.MySqlClient.MySqlProviderServices類,修改後大概就像下面的樣子。
private FieldInfo MySqlDbProviderServicesInstance
{
get
{
if (mySqlDbProviderServicesInstance == null)
{
//string fullName = Assembly.GetExecutingAssembly().FullName;
//fullName = fullName.Replace("MySql.Data", "MySql.Data.Entity");
string fullName = "MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity, Version=5.3.0.0, Culture=neutral, PublicKeyToken=b3fe30829fc170e4";
Type providerServicesType = Type.GetType(fullName, false);
mySqlDbProviderServicesInstance = providerServicesType.GetField("Instance",
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
}
return mySqlDbProviderServicesInstance;
}
}
object IServiceProvider.GetService(Type serviceType)
{
// DbProviderServices is the only service we offer up right now
if (serviceType != DbServicesType) return null;
if (MySqlDbProviderServicesInstance == null) return null;
return MySqlDbProviderServicesInstance.GetValue(null);
}
注意PublicKeyToken的值,要和MySQL.Data.Entity程序集對應。OK,再重新編譯得到MySQL.Data.dll和MySQL.Data.Entity.dll。
將這兩個文件安裝進GAC中。
接下來注冊我們的provider,打開machine.config,在system.data/DbProviderFactories節點中,添加下面的元素:
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient"
description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=5.3.0.0, Culture=neutral, PublicKeyToken=c66bfea3ae91850d" />
注意這裡程序集PublicKeyToken的值,要和MySQL.Data程序集的PublicKeyToken一致。
這樣,在我們的程序中就可以使用AEF for MySQL了,測試一下。
建立測試庫和測試表:
CREATE TABLE `mytable` (`ID` int(11) NOT NULL default '0',`NAME` varchar(100) default NULL,PRIMARY KEY (`ID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
對立對應的物理模型TestDB.ssdl:
<?xml version="1.0" encoding="utf-8"?>
<Schema Namespace="TestModel.Store" Alias="Self" Provider="MySql.Data.MySqlClient" ProviderManifestToken="MySQL" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">
<EntityContainer Name="Model3TargetContainer" >
<EntitySet Name="MYTABLE" EntityType="TestModel.Store.MYTABLE" store:Type="Tables" Schema="testdb" />
</EntityContainer>
<EntityType Name="MYTABLE">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="int" Nullable="false" />
<Property Name="NAME" Type="varchar" Nullable="true" MaxLength="40" />
</EntityType>
</Schema>
概念模型:TestDB.csdl
<?xml version="1.0" encoding="utf-8"?>
<Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm" Namespace="Model3" Alias="Self">
<EntityContainer Name="Model3Container1" >
<EntitySet Name="Company" EntityType="Model3.Company" />
</EntityContainer>
<EntityType Name="Company">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="Int32" Nullable="false" />
<Property Name="Name" Type="String" Nullable="true" />
</EntityType>
</Schema>
以及映射文件:TestDB.msl
<?xml version="1.0" encoding="utf-8"?>
<Mapping xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS" Space="C-S">
<Alias Key="Model" Value="Model3" />
<Alias Key="Target" Value="Model3.Target" />
<EntityContainerMapping CdmEntityContainer="Model3Container1" StorageEntityContainer="Model3TargetContainer">
<EntitySetMapping Name="Company">
<EntityTypeMapping TypeName="IsTypeOf(Model3.Company)">
<MappingFragment StoreEntitySet="MYTABLE">
<ScalarProperty Name="Name" ColumnName="NAME" />
<ScalarProperty Name="ID" ColumnName="ID" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
</EntityContainerMapping>
</Mapping>
這樣模型配置就完成了,我這裡概念模型和物理模型中的字段名和屬性名是不同的。
為了能以實體類的方式操作數據庫,利用下面的命令自動生成實體類文件:
edmgen /mode:EntityClassGeneration /incsdl:TestDB.csdl /namespace:Test /project:Test
把生成的文件包含到項目中,測試代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Entity;
namespace MySql.Data.Entity.Tests
{
class programe
{
static void Main()
{
using (Model3.Model3Container1 db = new Model3.Model3Container1(GetConnectionString()))
{
var coms = from com in db.Company
where com.ID < 50
select com;
foreach (var item in coms)
{
Console.WriteLine(item.Name);
}
}
Console.Read();
}
private static string GetConnectionString()
{
return String.Format(
"metadata=TestDB.csdl|TestDB.msl|TestDB.ssdl;provider=MySql.Data.MySqlClient; provider connection string=\"{0}\""
, "User Id=root;Password=root;Host=192.168.1.152;Database=testdb;Persist Security Info=True");
}
}
}
到這裡為止已經能夠正常讀取出數據,但是由於該組件還未正式發布,筆者也未進行詳細的測試,穩定性、可靠性可能存在一定問題,希望有興趣的朋友一起研究和學習,對在項目中急需使用AEF for MySQL的朋友能有所幫助。
最後提供兩個DLL文件的下載:AEF for MYSQL:http://download.csdn.net/detail/wisdomqq/954586