Entity Framework 实体框架的形成之旅--Code First的框架设计(5)
在前面几篇介绍了Entity Framework 实体框架的形成过程,整体框架主要是基于Database First的方式构建,也就是利用EDMX文件的映射关系,构建表与表之间的关系,这种模式弹性好,也可以利用图形化的设计器来设计表之间的关系,是开发项目较多采用的模式,不过问题还是这个XML太过复杂,因此有时候也想利用Code First模式构建整个框架。本文主要介绍利用Code First 来构建整个框架的过程以及碰到的问题探讨。
1、基于SqlServer的Code First模式
为了快速了解Code First的工作模式,我们先以微软自身的SQLServer数据库进行开发测试,我们还是按照常规的模式先构建一个标准关系的数据库,如下所示。

这个表包含了几个经典的关系,一个是自引用关系的Role表,一个是User和Role表的多对多关系,一个是User和UserDetail之间的引用关系。
一般情况下,能处理好这几种关系,基本上就能满足大多数项目上的要求了。这几个表的数据库脚本如下所示。
create table dbo.Role (
ID nvarchar(50) not null,
Name nvarchar(50) null,
ParentID nvarchar(50) null,
constraint PK_ROLE primary key (ID)
)
go create table dbo."User" (
ID nvarchar(50) not null,
Account nvarchar(50) null,
Password nvarchar(50) null,
constraint PK_USER primary key (ID)
)
go create table dbo.UserDetail (
ID nvarchar(50) not null,
User_ID nvarchar(50) null,
Name nvarchar(50) null,
Sex int null,
Birthdate datetime null,
Height decimal null,
Note ntext null,
constraint PK_USERDETAIL primary key (ID)
)
go create table dbo.UserRole (
User_ID nvarchar(50) not null,
Role_ID nvarchar(50) not null,
constraint PK_USERROLE primary key (User_ID, Role_ID)
)
go alter table dbo.Role
add constraint FK_ROLE_REFERENCE_ROLE foreign key (ParentID)
references dbo.Role (ID)
go alter table dbo.UserDetail
add constraint FK_USERDETA_REFERENCE_USER foreign key (User_ID)
references dbo."User" (ID)
go alter table dbo.UserRole
add constraint FK_USERROLE_REFERENCE_ROLE foreign key (Role_ID)
references dbo.Role (ID)
go alter table dbo.UserRole
add constraint FK_USERROLE_REFERENCE_USER foreign key (User_ID)
references dbo."User" (ID)
go
我们采用刚才介绍的Code Frist方式来构建实体框架,如下面几个步骤所示。
1)选择来自数据库的Code First方式。

2)选择指定的数据库连接,并选择对应的数据库表,如下所示(包括中间表UserRole)。

生成项目后,项目工程会增加几个类,包括Role实体类,User实体类,UserDetail实体类(没有中间表UserRole的实体类),还有一个是包含这些实体类的数据库上下文关系,它们的表之间的关系,是通过代码指定的,没有了EDMX文件了。
几个类文件的代码如下所示,其中实体类在类定义的头部,增加了[Table("Role")]的说明,表明了这个实体类和数据库表之间的关系。
[Table("Role")]
public partial class Role
{
public Role()
{
Children = new HashSet<Role>();
Users = new HashSet<User>();
}
[StringLength(50)]
public string ID { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string ParentID { get; set; }
public virtual ICollection<Role> Children { get; set; }
public virtual Role Parent { get; set; }
public virtual ICollection<User> Users { get; set; }
}
其他类如下所示。
[Table("User")]
public partial class User
{
public User()
{
UserDetails = new HashSet<UserDetail>();
Roles = new HashSet<Role>();
}
[StringLength(50)]
public string ID { get; set; }
[StringLength(50)]
public string Account { get; set; }
[StringLength(50)]
public string Password { get; set; }
public virtual ICollection<UserDetail> UserDetails { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
[Table("UserDetail")]
public partial class UserDetail
{
[StringLength(50)]
public string ID { get; set; }
[StringLength(50)]
public string User_ID { get; set; }
[StringLength(50)]
public string Name { get; set; }
public int? Sex { get; set; }
public DateTime? Birthdate { get; set; }
public decimal? Height { get; set; }
[Column(TypeName = "ntext")]
public string Note { get; set; }
public virtual User User { get; set; }
}
还有一个就是生成的数据库上下文的类。
public partial class DbEntities : DbContext
{
public DbEntities() : base("name=Model1")
{
}
public virtual DbSet<Role> Roles { get; set; }
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<UserDetail> UserDetails { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Role>()
.HasMany(e => e.Children)
.WithOptional(e => e.Parent)
.HasForeignKey(e => e.ParentID); modelBuilder.Entity<Role>()
.HasMany(e => e.Users)
.WithMany(e => e.Roles)
.Map(m => m.ToTable("UserRole")); modelBuilder.Entity<User>()
.HasMany(e => e.UserDetails)
.WithOptional(e => e.User)
.HasForeignKey(e => e.User_ID); modelBuilder.Entity<UserDetail>()
.Property(e => e.Height)
.HasPrecision(, );
}
}
上面这个数据库上下文的操作类,通过在OnModelCreating函数里面使用代码方式指定了几个表之间的关系,代替了EDMX文件的描述。
这样好像看起来比EDMX文件简单了很多,感觉很开心,一切就那么顺利。
如果我们使用这个数据库上下文进行数据库的插入,也是很顺利的执行,并包含了的多个表之间的关系处理,代码如下所示。
private void NormalTest()
{
DbEntities db = new DbEntities();
Role role = new Role() { ID = Guid.NewGuid().ToString(), Name = "test33" }; User user = new User() { ID = Guid.NewGuid().ToString(), Account = "test33", Password = "test33" };
UserDetail detail = new UserDetail() { ID = Guid.NewGuid().ToString(), Name = "userName33", Sex = , Note = "测试内容33", Height = };
user.UserDetails.Add(detail); role.Users.Add(user); db.Roles.Add(role);
db.SaveChanges(); List<Role> list = db.Roles.ToList();
}
我们发现,通过上面代码的操作,几个表都写入了数据,已经包含了他们之间的引用关系了。
2、基于泛型的仓储模式实体框架的提炼
为了更好对不同数据库的封装,我引入了前面介绍的基于泛型的仓储模式实体框架的结构,希望后面能够兼容多种数据库的支持,最终构建代码的分层结构如下所示。

使用这种框架的分层,相当于为各个数据库访问提供了统一标准的通用接口,为我们利用各种强大的基类快速实现各种功能提供了很好的保障。使用这种分层的框架代码如下所示。
private void FrameworkTest()
{
Role role = new Role() { ID = Guid.NewGuid().ToString(), Name = "test33" }; User user = new User() { ID = Guid.NewGuid().ToString(), Account = "test33", Password = "test33" };
UserDetail detail = new UserDetail() { ID = Guid.NewGuid().ToString(), Name = "userName33", Sex = , Note = "测试内容33", Height = };
user.UserDetails.Add(detail); role.Users.Add(user); IFactory.Instance<IRoleBLL>().Insert(role); ICollection<Role> list = IFactory.Instance<IRoleBLL>().GetAll(); }
我们发现,这部分代码执行的效果和纯粹使用自动生成的数据库上下文DbEntities 来操作数据库一样,能够写入各个表的数据,并添加了相关的应用关系。
满以为这样也可以很容易扩展到Oracle数据库上,但使用SQLServer数据库生成的实体类,在Oracle数据库访问的时候,发现它生成的实体类名称全部是大写,一旦修改为Camel驼峰格式的字段,就会出现找不到对应表字段的错误。
寻找了很多解决方案,依旧无法有效避免这个问题,因为Oracle本身的表或者字段名称是大小写敏感的,关于Oracle这个问题,先关注后续解决吧,不过对于如果不考虑支持多种数据库的话,基于SQLServer数据库的Code First构建框架真的还是比较方便,我们不用维护那个比较麻烦的EDMX文件,只需要在代码函数里面动态添加几个表之间的关系即可。
这个系列文章索引如下:
Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)
Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)
Entity Framework 实体框架的形成之旅--基类接口的统一和异步操作的实现(3)
Entity Framework 实体框架的形成之旅--实体数据模型 (EDM)的处理(4)
Entity Framework 实体框架的形成之旅--Code First的框架设计(5)
Entity Framework 实体框架的形成之旅--Code First的框架设计(5)的更多相关文章
- Entity Framework 实体框架的形成之旅--几种数据库操作的代码介绍(9)
本篇主要对常规数据操作的处理和实体框架的处理代码进行对比,以便更容易学习理解实体框架里面,对各种数据库处理技巧,本篇介绍几种数据库操作的代码,包括写入中间表操作.联合中间表获取对象集合.递归操作.设置 ...
- Entity Framework 实体框架的形成之旅--界面操作的几个典型的处理(8)
在上篇随笔<Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合>里面,介绍了在Entity Framework 实体框架里面引入了 ...
- Entity Framework 实体框架的形成之旅--数据传输模型DTO和实体模型Entity的分离与联合
在使用Entity Framework 实体框架的时候,我们大多数时候操作的都是实体模型Entity,这个和数据库操作上下文结合,可以利用LINQ等各种方便手段,实现起来非常方便,一切看起来很美好.但 ...
- Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)
在前面的随笔<Entity Framework 实体框架的形成之旅--Code First的框架设计(5)>里介绍了基于Code First模式的实体框架的经验,这种方式自动处理出来的模式 ...
- Entity Framework 实体框架的形成之旅--实体数据模型 (EDM)的处理(4)
在前面几篇关于Entity Framework 实体框架的介绍里面,已经逐步对整个框架进行了一步步的演化,以期达到统一.高效.可重用性等目的,本文继续探讨基于泛型的仓储模式实体框架方面的改进优化,使我 ...
- Entity Framework 实体框架的形成之旅--实体框架的开发的几个经验总结
在前阵子,我对实体框架进行了一定的研究,然后把整个学习的过程开了一个系列,以逐步深入的方式解读实体框架的相关技术,期间每每碰到一些新的问题需要潜入研究.本文继续前面的主题介绍,着重从整体性的来总结一下 ...
- Entity Framework 实体框架的形成之旅--为基础类库接口增加单元测试,对基类接口进行正确性校验(10)
本篇介绍Entity Framework 实体框架的文章已经到了第十篇了,对实体框架的各个分层以及基类的封装管理,已经臻于完善,为了方便对基类接口的正确性校验,以及方便对以后完善或扩展接口进行回归测试 ...
- Entity Framework 实体框架的形成之旅--基类接口的统一和异步操作的实现(3)
在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...
- Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)
在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...
随机推荐
- JavaScript字符转Unicode,顺便说句:GitHub的Oh no页面很亮
遇到个输不出来的字符怎么办,因为输不出来的字符一般又是不常见大多数时候连名字也喊不出来的,所以想问百度谷歌大大也不大可能.如果是小白用户肯定会去把输入法软盘打开切换到其他键盘一个一个找.即使有搜狗输入 ...
- React Native01-开始 Windows环境安装配置篇
转载本文章的童鞋请注明原链接. 查阅文档之类的资料,建议到 http://reactnative.cn/ 本人使用环境Win10. 在阅读本文之前,请了解我们安装React Native之前,要安装P ...
- osgi 1
Helloworld入门 准备: eclipse 3.4 需要jar,—— eclipse 自带的,plugin下面有很多,抛开里面的jar,很多都是当前项目不需要的,如果不适用eclipse而是直接 ...
- Atitit 语音识别的技术原理
Atitit 语音识别的技术原理 1.1. 语音识别技术,也被称为自动语音识别Automatic Speech Recognition,(ASR),2 1.2. 模型目前,主流的大词汇量语音识别系统多 ...
- Android笔记——探究活动
1.活动是什么 活动(Activity)是最容易吸引到用户的地方了,它是一种可以包含用户界面的组件,主要用于和用户进行交互.一个应用程序中可以包含零个或多个活动,但不包含任何活动的应用程序 ...
- oracle 中 rownum 和 row_number()
简单的介绍下oracle 中rownum 和 row_number() 使用,实例演示. 参照:http://www.cnblogs.com/zjrstar/archive/2006/08/31/49 ...
- css绘制三角形原理
1.新建一个元素,将它的宽高都设置为0:然后通过设置border属性来实现三角形效果,下面是css绘制三角形的原理: <!DOCTYPE html> <html> <he ...
- Jetty 服务器的知识
Jetty 服务器的知识 也许你还没有听说过这个Jetty服务器,不过它确实是一种比较轻量级的Java服务器,和Tomcat一样,专门解释JavaWeb程序的服务器.因为在之前学习Java Web 的 ...
- ASP.NET MVC中简单使用Autofac
项目中引入Autofac的目的是为了实现控制反转,即IoC,Inversion of Control.控制反转可以有效的降低类之间的相互依赖关系,增加架构的弹性,降低软件复杂度. 示例代码: IPro ...
- 仿SGI STL的traits技法
首先是iterator traits,这个是用来萃取迭代器的特性的 #ifndef _STL_ITERATOR_H_ #define _STL_ITERATOR_H_ #include <cst ...