前言
上一篇文章中,我詳細解析了使用Database First和Model First開發模式自動生成的Entity Framework實體數據模型的內容結構,如下圖所示:
圖1實體數據模型內容結構圖
本文將就實體數據模型內容作文章,將其拆分為多個文件,並作適當的調整,實現一個DIY的實體數據模型,其內容結構如下圖所示:
圖2調整后的實體數據模型內容結構圖
做這些調整的目的有兩個,其一是使用POCO替換實體數據模型中繁瑣的實體類,使代碼更整潔並易於維護;其二是使程序支持多種數據庫,並且易於擴展。
E-R模型
E-R模型繼續沿用上一篇文章中使用的模型,如下圖所示:
圖3 E-R模型
對應的SQL Server 數據庫DDL語句如下:
1 --創建表 2 CREATE TABLE [Role]( 3 [ID] [uniqueidentifier] NOT NULL, 4 [Name] [nvarchar](40) NOT NULL, 5 [ParentID] [uniqueidentifier] NULL) 6 GO 7 8 CREATE TABLE [User]( 9 [ID] [uniqueidentifier] NOT NULL, 10 [Account] [nvarchar](50) NOT NULL, 11 [Password] [varchar](50) NOT NULL) 12 GO 13 14 CREATE TABLE [UserDetail]( 15 [ID] [uniqueidentifier] NOT NULL, 16 [Name] [nvarchar](50) NOT NULL, 17 [Sex] [nvarchar](2) NULL, 18 [Birthday] [datetime] NULL) 19 GO 20 21 CREATE TABLE [UserRole]( 22 [UserID] [uniqueidentifier] NOT NULL, 23 [RoleID] [uniqueidentifier] NOT NULL) 24 GO 25 26 --創建主鍵 27 ALTER TABLE [Role] 28 ADD CONSTRAINT [PK_Role] 29 PRIMARY KEY CLUSTERED ([ID] ASC); 30 GO 31 32 ALTER TABLE [User] 33 ADD CONSTRAINT [PK_User] 34 PRIMARY KEY CLUSTERED ([ID] ASC); 35 GO 36 37 ALTER TABLE [UserDetail] 38 ADD CONSTRAINT [PK_UserDetail] 39 PRIMARY KEY CLUSTERED ([ID] ASC); 40 GO 41 42 ALTER TABLE [UserRole] 43 ADD CONSTRAINT [PK_UserRole] 44 PRIMARY KEY CLUSTERED ([UserID] ASC, RoleID ASC); 45 GO 46 47 --創建外鍵 48 ALTER TABLE [Role] WITH CHECK ADD CONSTRAINT [FK_Role_Role] FOREIGN KEY([ParentID]) 49 REFERENCES [Role] ([ID]) 50 GO 51 52 ALTER TABLE [UserDetail] WITH CHECK ADD CONSTRAINT [FK_UserDetail_User] FOREIGN KEY([ID]) 53 REFERENCES [User] ([ID]) 54 ON DELETE CASCADE 55 GO 56 57 ALTER TABLE [UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_User] FOREIGN KEY([UserID]) 58 REFERENCES [User] ([ID]) 59 ON DELETE CASCADE 60 GO 61 62 ALTER TABLE [UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_Role] FOREIGN KEY([RoleID]) 63 REFERENCES [Role] ([ID]) 64 ON DELETE CASCADE 65 GO 66 67 --創建儲存過程 68 --SQL Server自關聯表無法通過外鍵設置級聯刪除,所以專門寫一個觸發器來完成該工作 69 CREATE TRIGGER TRG_Role_Delete 70 ON [Role] 71 INSTEAD OF DELETE 72 AS 73 BEGIN 74 -- SET NOCOUNT ON added to prevent extra result sets from 75 -- interfering with SELECT statements. 76 SET NOCOUNT ON; 77 78 DECLARE @ID uniqueidentifier; 79 SELECT @ID = ID FROM deleted; 80 81 DELETE [Role] WHERE ParentID = @ID; 82 DELETE [Role] WHERE ID = @ID; 83 END 84 GO
使用SQL Server Management Studio工具創建名為“Membership”的數據庫,並執行以上的DDL語句,建立本示例所需的數據庫對象。
DIY實體數據模型
接下來將對前文中的實體數據模型內容進行靈活的調整,使其支持POCO和多數據庫,調整的內容包括:
- 將Membership.Designer.cs文件中的上下文環境類放入單獨的EntityContext.cs文件中,並只保留構造函數和實體集屬性兩部分內容;
- 直接定義Role、User和UserDetail三個POCO實體類;
- 將Membership.edmx文件中CSDL、MSL和SSDL的內容分別放入Membership.csdl、Membership.msl和Membership.SqlServer.ssdl三個XML文件中;
- 復制Membership.SqlServer.ssdl文件為Membership.MySQL.ssdl文件,並依據MySQL數據庫SQL方言,替換相應的數據類型。
一、實體上下文環境
1 public class EntityContext : ObjectContext 2 { 3 public EntityContext() : this("name=Membership") 4 { 5 this.ContextOptions.LazyLoadingEnabled = true; 6 } 7 8 public EntityContext(string connectionString) : base(connectionString, "Membership") 9 { 10 this.ContextOptions.LazyLoadingEnabled = true; 11 } 12 13 public EntityContext(EntityConnection connection) : base(connection, "Membership") 14 { 15 this.ContextOptions.LazyLoadingEnabled = true; 16 } 17 18 private ObjectSet<Role> roles; 19 public ObjectSet<Role> Roles 20 { 21 get 22 { 23 if ((roles == null)) 24 roles = base.CreateObjectSet<Role>("Roles"); 25 26 return roles; 27 } 28 } 29 30 private ObjectSet<User> users; 31 public ObjectSet<User> Users 32 { 33 get 34 { 35 if ((users == null)) 36 { 37 users = base.CreateObjectSet<User>("Users"); 38 } 39 return users; 40 } 41 } 42 43 private ObjectSet<UserDetail> userDetails; 44 public ObjectSet<UserDetail> UserDetails 45 { 46 get 47 { 48 if ((userDetails == null)) 49 { 50 userDetails = base.CreateObjectSet<UserDetail>("UserDetails"); 51 } 52 return userDetails; 53 } 54 } 55 }
二、實體類
Role實體類:
1 public class Role 2 { 3 public Guid ID { get; set; } 4 5 public string Name { get; set; } 6 7 public Guid? ParentID { get; set; } 8 9 public Role Parent { get; set; } 10 11 public IList<Role> Children { get; set; } 12 13 public IList<User> Users { get; set; } 14 }
User實體類:
1 public class User 2 { 3 public Guid ID { get; set; } 4 5 public string Account { get; set; } 6 7 public string Password { get; set; } 8 9 public UserDetail UserDetail { get; set; } 10 11 public IList<Role> Roles { get; set; } 12 }
UserDetail實體類:
1 public class UserDetail 2 { 3 public Guid ID { get; set; } 4 5 public string Name { get; set; } 6 7 public string Sex { get; set; } 8 9 public DateTime Birthday { get; set; } 10 11 public User User { get; set; } 12 }
三、CSDL
1 <?xml version="1.0" encoding="utf-8" ?> 2 <Schema Namespace="MembershipModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm"> 3 <EntityContainer Name="Membership" annotation:LazyLoadingEnabled="true"> 4 <EntitySet Name="Roles" EntityType="MembershipModel.Role" /> 5 <EntitySet Name="Users" EntityType="MembershipModel.User" /> 6 <EntitySet Name="UserDetails" EntityType="MembershipModel.UserDetail" /> 7 <AssociationSet Name="FK_Role_Role" Association="MembershipModel.FK_Role_Role"> 8 <End Role="Parent" EntitySet="Roles" /> 9 <End Role="Children" EntitySet="Roles" /> 10 </AssociationSet> 11 <AssociationSet Name="FK_UserDetail_User" Association="MembershipModel.FK_UserDetail_User"> 12 <End Role="User" EntitySet="Users" /> 13 <End Role="UserDetail" EntitySet="UserDetails" /> 14 </AssociationSet> 15 <AssociationSet Name="UserRole" Association="MembershipModel.UserRole"> 16 <End Role="Role" EntitySet="Roles" /> 17 <End Role="User" EntitySet="Users" /> 18 </AssociationSet> 19 </EntityContainer> 20 <EntityType Name="Role"> 21 <Key> 22 <PropertyRef Name="ID" /> 23 </Key> 24 <Property Name="ID" Type="Guid" Nullable="false" /> 25 <Property Name="Name" Type="String" Nullable="false" MaxLength="40" Unicode="true" FixedLength="false" /> 26 <Property Name="ParentID" Type="Guid" /> 27 <NavigationProperty Name="Children" Relationship="MembershipModel.FK_Role_Role" FromRole="Parent" ToRole="Children" /> 28 <NavigationProperty Name="Parent" Relationship="MembershipModel.FK_Role_Role" FromRole="Children" ToRole="Parent" /> 29 <NavigationProperty Name="Users" Relationship="MembershipModel.UserRole" FromRole="Role" ToRole="User" /> 30 </EntityType> 31 <EntityType Name="User"> 32 <Key> 33 <PropertyRef Name="ID" /> 34 </Key> 35 <Property Name="ID" Type="Guid" Nullable="false" /> 36 <Property Name="Account" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" /> 37 <Property Name="Password" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" /> 38 <NavigationProperty Name="UserDetail" Relationship="MembershipModel.FK_UserDetail_User" FromRole="User" ToRole="UserDetail" /> 39 <NavigationProperty Name="Roles" Relationship="MembershipModel.UserRole" FromRole="User" ToRole="Role" /> 40 </EntityType> 41 <EntityType Name="UserDetail"> 42 <Key> 43 <PropertyRef Name="ID" /> 44 </Key> 45 <Property Name="ID" Type="Guid" Nullable="false" /> 46 <Property Name="Name" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" /> 47 <Property Name="Sex" Type="String" MaxLength="2" Unicode="true" FixedLength="false" /> 48 <Property Name="Birthday" Type="DateTime" /> 49 <NavigationProperty Name="User" Relationship="MembershipModel.FK_UserDetail_User" FromRole="UserDetail" ToRole="User" /> 50 </EntityType> 51 <Association Name="FK_Role_Role"> 52 <End Role="Parent" Type="MembershipModel.Role" Multiplicity="0..1" /> 53 <End Role="Children" Type="MembershipModel.Role" Multiplicity="*" /> 54 <ReferentialConstraint> 55 <Principal Role="Parent"> 56 <PropertyRef Name="ID" /> 57 </Principal> 58 <Dependent Role="Children"> 59 <PropertyRef Name="ParentID" /> 60 </Dependent> 61 </ReferentialConstraint> 62 </Association> 63 <Association Name="FK_UserDetail_User"> 64 <End Role="User" Type="MembershipModel.User" Multiplicity="1"> 65 <OnDelete Action="Cascade" /> 66 </End> 67 <End Role="UserDetail" Type="MembershipModel.UserDetail" Multiplicity="0..1" /> 68 <ReferentialConstraint> 69 <Principal Role="User"> 70 <PropertyRef Name="ID" /> 71 </Principal> 72 <Dependent Role="UserDetail"> 73 <PropertyRef Name="ID" /> 74 </Dependent> 75 </ReferentialConstraint> 76 </Association> 77 <Association Name="UserRole"> 78 <End Role="Role" Type="MembershipModel.Role" Multiplicity="*" /> 79 <End Role="User" Type="MembershipModel.User" Multiplicity="*" /> 80 </Association> 81 </Schema>
四、MSL
1 <?xml version="1.0" encoding="utf-8" ?> 2 <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs"> 3 <EntityContainerMapping StorageEntityContainer="MembershipModelStoreContainer" CdmEntityContainer="Membership"> 4 <EntitySetMapping Name="Roles"> 5 <EntityTypeMapping TypeName="MembershipModel.Role"> 6 <MappingFragment StoreEntitySet="Role"> 7 <ScalarProperty Name="ID" ColumnName="ID" /> 8 <ScalarProperty Name="Name" ColumnName="Name" /> 9 <ScalarProperty Name="ParentID" ColumnName="ParentID" /> 10 </MappingFragment> 11 </EntityTypeMapping> 12 </EntitySetMapping> 13 <EntitySetMapping Name="Users"> 14 <EntityTypeMapping TypeName="MembershipModel.User"> 15 <MappingFragment StoreEntitySet="User"> 16 <ScalarProperty Name="ID" ColumnName="ID" /> 17 <ScalarProperty Name="Account" ColumnName="Account" /> 18 <ScalarProperty Name="Password" ColumnName="Password" /> 19 </MappingFragment> 20 </EntityTypeMapping> 21 </EntitySetMapping> 22 <EntitySetMapping Name="UserDetails"> 23 <EntityTypeMapping TypeName="MembershipModel.UserDetail"> 24 <MappingFragment StoreEntitySet="UserDetail"> 25 <ScalarProperty Name="ID" ColumnName="ID" /> 26 <ScalarProperty Name="Name" ColumnName="Name" /> 27 <ScalarProperty Name="Sex" ColumnName="Sex" /> 28 <ScalarProperty Name="Birthday" ColumnName="Birthday" /> 29 </MappingFragment> 30 </EntityTypeMapping> 31 </EntitySetMapping> 32 <AssociationSetMapping Name="UserRole" TypeName="MembershipModel.UserRole" StoreEntitySet="UserRole"> 33 <EndProperty Name="Role"> 34 <ScalarProperty Name="ID" ColumnName="RoleID" /> 35 </EndProperty> 36 <EndProperty Name="User"> 37 <ScalarProperty Name="ID" ColumnName="UserID" /> 38 </EndProperty> 39 </AssociationSetMapping> 40 </EntityContainerMapping> 41 </Mapping>
五、SSDL
Membership.SqlServer.ssdl
1 <?xml version="1.0" encoding="utf-8" ?> 2 <Schema Namespace="MembershipModel.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"> 3 <EntityContainer Name="MembershipModelStoreContainer"> 4 <EntitySet Name="Role" EntityType="MembershipModel.Store.Role" store:Type="Tables" Schema="dbo" /> 5 <EntitySet Name="User" EntityType="MembershipModel.Store.User" store:Type="Tables" Schema="dbo" /> 6 <EntitySet Name="UserDetail" EntityType="MembershipModel.Store.UserDetail" store:Type="Tables" Schema="dbo" /> 7 <EntitySet Name="UserRole" EntityType="MembershipModel.Store.UserRole" store:Type="Tables" Schema="dbo" /> 8 <AssociationSet Name="FK_Role_Role" Association="MembershipModel.Store.FK_Role_Role"> 9 <End Role="Parent" EntitySet="Role" /> 10 <End Role="Children" EntitySet="Role" /> 11 </AssociationSet> 12 <AssociationSet Name="FK_UserDetail_User" Association="MembershipModel.Store.FK_UserDetail_User"> 13 <End Role="User" EntitySet="User" /> 14 <End Role="UserDetail" EntitySet="UserDetail" /> 15 </AssociationSet> 16 <AssociationSet Name="FK_UserRole_Role" Association="MembershipModel.Store.FK_UserRole_Role"> 17 <End Role="Role" EntitySet="Role" /> 18 <End Role="UserRole" EntitySet="UserRole" /> 19 </AssociationSet> 20 <AssociationSet Name="FK_UserRole_User" Association="MembershipModel.Store.FK_UserRole_User"> 21 <End Role="User" EntitySet="User" /> 22 <End Role="UserRole" EntitySet="UserRole" /> 23 </AssociationSet> 24 </EntityContainer> 25 <EntityType Name="Role"> 26 <Key> 27 <PropertyRef Name="ID" /> 28 </Key> 29 <Property Name="ID" Type="uniqueidentifier" Nullable="false" /> 30 <Property Name="Name" Type="nvarchar" Nullable="false" MaxLength="40" /> 31 <Property Name="ParentID" Type="uniqueidentifier" /> 32 </EntityType> 33 <EntityType Name="User"> 34 <Key> 35 <PropertyRef Name="ID" /> 36 </Key> 37 <Property Name="ID" Type="uniqueidentifier" Nullable="false" /> 38 <Property Name="Account" Type="nvarchar" Nullable="false" MaxLength="50" /> 39 <Property Name="Password" Type="varchar" Nullable="false" MaxLength="50" /> 40 </EntityType> 41 <EntityType Name="UserDetail"> 42 <Key> 43 <PropertyRef Name="ID" /> 44 </Key> 45 <Property Name="ID" Type="uniqueidentifier" Nullable="false" /> 46 <Property Name="Name" Type="nvarchar" Nullable="false" MaxLength="50" /> 47 <Property Name="Sex" Type="nvarchar" MaxLength="2" /> 48 <Property Name="Birthday" Type="datetime" /> 49 </EntityType> 50 <EntityType Name="UserRole"> 51 <Key> 52 <PropertyRef Name="UserID" /> 53 <PropertyRef Name="RoleID" /> 54 </Key> 55 <Property Name="UserID" Type="uniqueidentifier" Nullable="false" /> 56 <Property Name="RoleID" Type="uniqueidentifier" Nullable="false" /> 57 </EntityType> 58 <Association Name="FK_Role_Role"> 59 <End Role="Parent" Type="MembershipModel.Store.Role" Multiplicity="0..1" /> 60 <End Role="Children" Type="MembershipModel.Store.Role" Multiplicity="*" /> 61 <ReferentialConstraint> 62 <Principal Role="Parent"> 63 <PropertyRef Name="ID" /> 64 </Principal> 65 <Dependent Role="Children"> 66 <PropertyRef Name="ParentID" /> 67 </Dependent> 68 </ReferentialConstraint> 69 </Association> 70 <Association Name="FK_UserDetail_User"> 71 <End Role="User" Type="MembershipModel.Store.User" Multiplicity="1"> 72 <OnDelete Action="Cascade" /> 73 </End> 74 <End Role="UserDetail" Type="MembershipModel.Store.UserDetail" Multiplicity="0..1" /> 75 <ReferentialConstraint> 76 <Principal Role="User"> 77 <PropertyRef Name="ID" /> 78 </Principal> 79 <Dependent Role="UserDetail"> 80 <PropertyRef Name="ID" /> 81 </Dependent> 82 </ReferentialConstraint> 83 </Association> 84 <Association Name="FK_UserRole_Role"> 85 <End Role="Role" Type="MembershipModel.Store.Role" Multiplicity="1"> 86 <OnDelete Action="Cascade" /> 87 </End> 88 <End Role="UserRole" Type="MembershipModel.Store.UserRole" Multiplicity="*" /> 89 <ReferentialConstraint> 90 <Principal Role="Role"> 91 <PropertyRef Name="ID" /> 92 </Principal> 93 <Dependent Role="UserRole"> 94 <PropertyRef Name="RoleID" /> 95 </Dependent> 96 </ReferentialConstraint> 97 </Association> 98 <Association Name="FK_UserRole_User"> 99 <End Role="User" Type="MembershipModel.Store.User" Multiplicity="1"> 100 <OnDelete Action="Cascade" /> 101 </End> 102 <End Role="UserRole" Type="MembershipModel.Store.UserRole" Multiplicity="*" /> 103 <ReferentialConstraint> 104 <Principal Role="User"> 105 <PropertyRef Name="ID" /> 106 </Principal> 107 <Dependent Role="UserRole"> 108 <PropertyRef Name="UserID" /> 109 </Dependent> 110 </ReferentialConstraint> 111 </Association> 112 </Schema>
模型應用
首先需要在應用程序配置文件中配置數據連接:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <connectionStrings> 4 <!--SQL Server--> 5 <add name="Membership" providerName="System.Data.EntityClient" connectionString="provider=System.Data.SqlClient;provider connection string=" Data Source=localhost; User Id=sa; Password=11111111; Initial Catalog=Membership; Integrated Security=False;"; metadata=..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.SqlServer.ssdl|..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.csdl|..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.msl"/> 6 </connectionStrings> 7 </configuration>
然后就可以使用該實體數據模型了,測試示例代碼如下:
1 using (var db = new EntityContext()) 2 { 3 var role = new Role(); 4 role.ID = Guid.NewGuid(); 5 role.Name = "員工"; 6 7 var role1 = new Role(); 8 role1.ID = Guid.NewGuid(); 9 role1.Name = "部門經理"; 10 role1.Parent = role; 11 db.Roles.AddObject(role1); 12 13 db.SaveChanges(); 14 }
多數據庫支持
下面以擴展對MySQL數據庫支持為例,講解該實體數據模型如何實現對多種數據庫的支持。需要做以下三件事情:
首先,編寫MySQL數據庫的DDL語句,並執行它以生成數據庫(我是使用Navicat工具連接MySQL,創建Membership數據庫,然后執行DDL語句)。DDL語句如下:
1 CREATE TABLE `Role` ( 2 `ID` char(36) NOT NULL, 3 `Name` varchar(40) NOT NULL, 4 `ParentID` char(36) NULL, 5 PRIMARY KEY (`ID`), 6 KEY `ParentID` (`ParentID`), 7 CONSTRAINT `FK_Role_Role` FOREIGN KEY (`ParentID`) REFERENCES `Role` (`ID`) ON DELETE CASCADE 8 ); 9 10 CREATE TABLE `User` ( 11 `ID` char(36) NOT NULL, 12 `Account` varchar(50) NOT NULL, 13 `Password` varchar(50) NOT NULL, 14 PRIMARY KEY (`ID`) 15 ); 16 17 CREATE TABLE `UserDetail` ( 18 `ID` char(36) NOT NULL, 19 `Name` varchar(50) NOT NULL, 20 `Sex` varchar(2) NULL, 21 `Birthday` datetime DEFAULT NULL, 22 PRIMARY KEY (`ID`), 23 CONSTRAINT `FK_UserDetail_User` FOREIGN KEY (`ID`) REFERENCES `user` (`ID`) ON DELETE CASCADE 24 ); 25 26 CREATE TABLE `UserRole` ( 27 `UserID` char(36) NOT NULL, 28 `RoleID` char(36) NOT NULL, 29 PRIMARY KEY (`UserID`,`RoleID`), 30 KEY `FK_UserRole_Role` (`RoleID`), 31 CONSTRAINT `FK_UserRole_User` FOREIGN KEY (`UserID`) REFERENCES `User` (`ID`) ON DELETE CASCADE, 32 CONSTRAINT `FK_UserRole_Role` FOREIGN KEY (`RoleID`) REFERENCES `Role` (`ID`) ON DELETE CASCADE 33 );
然后,添加Membership.MySQL.ssdl文件,其內容與Membership.SqlServer.ssdl的差別主要體現在提供程序及其版本、數據類型上,如下內容中的高亮標識所示:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <Schema Namespace="MembershipModel.Store" Alias="Self" Provider="MySql.Data.MySqlClient" ProviderManifestToken="5.5" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl"> 3 <EntityContainer Name="MembershipModelStoreContainer"> 4 <EntitySet Name="Role" EntityType="MembershipModel.Store.Role" store:Type="Tables" Schema="dbo" /> 5 <EntitySet Name="User" EntityType="MembershipModel.Store.User" store:Type="Tables" Schema="dbo" /> 6 <EntitySet Name="UserDetail" EntityType="MembershipModel.Store.UserDetail" store:Type="Tables" Schema="dbo" /> 7 <EntitySet Name="UserRole" EntityType="MembershipModel.Store.UserRole" store:Type="Tables" Schema="dbo" /> 8 <AssociationSet Name="FK_Role_Role" Association="MembershipModel.Store.FK_Role_Role"> 9 <End Role="Parent" EntitySet="Role" /> 10 <End Role="Children" EntitySet="Role" /> 11 </AssociationSet> 12 <AssociationSet Name="FK_UserDetail_User" Association="MembershipModel.Store.FK_UserDetail_User"> 13 <End Role="User" EntitySet="User" /> 14 <End Role="UserDetail" EntitySet="UserDetail" /> 15 </AssociationSet> 16 <AssociationSet Name="FK_UserRole_Role" Association="MembershipModel.Store.FK_UserRole_Role"> 17 <End Role="Role" EntitySet="Role" /> 18 <End Role="UserRole" EntitySet="UserRole" /> 19 </AssociationSet> 20 <AssociationSet Name="FK_UserRole_User" Association="MembershipModel.Store.FK_UserRole_User"> 21 <End Role="User" EntitySet="User" /> 22 <End Role="UserRole" EntitySet="UserRole" /> 23 </AssociationSet> 24 </EntityContainer> 25 <EntityType Name="Role"> 26 <Key> 27 <PropertyRef Name="ID" /> 28 </Key> 29 <Property Name="ID" Type="guid" Nullable="false" /> 30 <Property Name="Name" Type="nvarchar" Nullable="false" MaxLength="40" /> 31 <Property Name="ParentID" Type="guid" /> 32 </EntityType> 33 <EntityType Name="User"> 34 <Key> 35 <PropertyRef Name="ID" /> 36 </Key> 37 <Property Name="ID" Type="guid" Nullable="false" /> 38 <Property Name="Account" Type="nvarchar" Nullable="false" MaxLength="50" /> 39 <Property Name="Password" Type="varchar" Nullable="false" MaxLength="50" /> 40 </EntityType> 41 <EntityType Name="UserDetail"> 42 <Key> 43 <PropertyRef Name="ID" /> 44 </Key> 45 <Property Name="ID" Type="guid" Nullable="false" /> 46 <Property Name="Name" Type="nvarchar" Nullable="false" MaxLength="50" /> 47 <Property Name="Sex" Type="nvarchar" MaxLength="2" /> 48 <Property Name="Birthday" Type="datetime" /> 49 </EntityType> 50 <EntityType Name="UserRole"> 51 <Key> 52 <PropertyRef Name="UserID" /> 53 <PropertyRef Name="RoleID" /> 54 </Key> 55 <Property Name="UserID" Type="guid" Nullable="false" /> 56 <Property Name="RoleID" Type="guid" Nullable="false" /> 57 </EntityType> 58 <Association Name="FK_Role_Role"> 59 <End Role="Parent" Type="MembershipModel.Store.Role" Multiplicity="0..1" /> 60 <End Role="Children" Type="MembershipModel.Store.Role" Multiplicity="*" /> 61 <ReferentialConstraint> 62 <Principal Role="Parent"> 63 <PropertyRef Name="ID" /> 64 </Principal> 65 <Dependent Role="Children"> 66 <PropertyRef Name="ParentID" /> 67 </Dependent> 68 </ReferentialConstraint> 69 </Association> 70 <Association Name="FK_UserDetail_User"> 71 <End Role="User" Type="MembershipModel.Store.User" Multiplicity="1"> 72 <OnDelete Action="Cascade" /> 73 </End> 74 <End Role="UserDetail" Type="MembershipModel.Store.UserDetail" Multiplicity="0..1" /> 75 <ReferentialConstraint> 76 <Principal Role="User"> 77 <PropertyRef Name="ID" /> 78 </Principal> 79 <Dependent Role="UserDetail"> 80 <PropertyRef Name="ID" /> 81 </Dependent> 82 </ReferentialConstraint> 83 </Association> 84 <Association Name="FK_UserRole_Role"> 85 <End Role="Role" Type="MembershipModel.Store.Role" Multiplicity="1"> 86 <OnDelete Action="Cascade" /> 87 </End> 88 <End Role="UserRole" Type="MembershipModel.Store.UserRole" Multiplicity="*" /> 89 <ReferentialConstraint> 90 <Principal Role="Role"> 91 <PropertyRef Name="ID" /> 92 </Principal> 93 <Dependent Role="UserRole"> 94 <PropertyRef Name="RoleID" /> 95 </Dependent> 96 </ReferentialConstraint> 97 </Association> 98 <Association Name="FK_UserRole_User"> 99 <End Role="User" Type="MembershipModel.Store.User" Multiplicity="1"> 100 <OnDelete Action="Cascade" /> 101 </End> 102 <End Role="UserRole" Type="MembershipModel.Store.UserRole" Multiplicity="*" /> 103 <ReferentialConstraint> 104 <Principal Role="User"> 105 <PropertyRef Name="ID" /> 106 </Principal> 107 <Dependent Role="UserRole"> 108 <PropertyRef Name="UserID" /> 109 </Dependent> 110 </ReferentialConstraint> 111 </Association> 112 </Schema>
配置文件中加入MySQL連接字符串,以及MySQL數據庫提供程序工廠,添加后的應用程序配置文件內容如下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <connectionStrings> 4 <!--SQL Server--> 5 <add name="Membership" providerName="System.Data.EntityClient" connectionString="provider=System.Data.SqlClient;provider connection string=" Data Source=localhost; User Id=sa; Password=11111111; Initial Catalog=Membership; Integrated Security=False;"; metadata=..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.SqlServer.ssdl|..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.csdl|..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.msl"/> 6 <!--MySQL 7 <add name="Membership" providerName="System.Data.EntityClient" connectionString="provider=MySql.Data.MySqlClient; provider connection string=" Data Source=localhost; User Id=root; Password=11111111; Initial Catalog=Membership; Integrated Security=False;"; metadata=..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.MySQL.ssdl|..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.csdl|..\..\..\Apollo.Blog.EF.Chapter4.Edm\Mapping\Membership.msl"/>--> 8 </connectionStrings> 9 <system.data> 10 <DbProviderFactories> 11 <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/> 12 </DbProviderFactories> 13 </system.data> 14 </configuration>
通過切換SQL Server和MySQL連接字符串的啟用和注釋狀態,就可以實現不同數據庫的支持切換了。
補充說明
一、關於數據庫生成
Entity Framework技術提供了由實體數據模型直接生成數據庫的功能,示例代碼如下:
1 using (var db = new EntityContext()) 2 { 3 if (!db.DatabaseExists()) 4 db.CreateDatabase(); 5 }
但是,通過該方式自動生成數據庫至少存在以下兩個問題或不足:
- 生成的外鍵不能級聯刪除,這會導致有外鍵的對象刪除出錯;
- 不支持復雜的DDL語句功能,比如無法生成存儲過程、觸發器等。
所以,我建議不要使用該方式自動生成數據庫,雖然它看起來貌似很好很強大。
二、關於映射文件的生成操作
將Membership.edmx文件拆分成SSDL、CSDL和MSL三個單獨的文件后,將這三個文件設為“嵌入的資源”,然后在應用配置文件的數據庫連接字符串中使用如下的方式查找文件似乎行不通,總是報“無法加載指定的元數據資源”錯誤,所以本文選擇了使用文件的相對路徑進行查找:
1 metadata=res://*/Membership.csdl|res://*/Membership.ssdl|res://*/Membership.msl
總結
本文在前文深入了解實體數據模型的基礎上,對該模型作了些許調整,實現了一個DIY的實體數據模型。該實體數據模型能夠很好的支持POCO和多數據庫,易於維護和擴展。但是該模型無法實現自動延遲加載,這算是美中不足之處。在本系列的第6篇中,將對延遲加載做專門討論,屆時將會告訴你如何使用該DIY實體數據模型實現手動延遲加載;以及如何修改該模型,使其支持延遲加載。
下一篇文章將討論如何在本文的基礎上實現關聯數據的延遲加載。