TinyFrame开篇:基于CodeFirst的ORM
前言
做项目的这段时间,由于比较忙,一直没有机会闲下来思考。正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做:TinyFrame吧。顾名思义,就是微框架的意思。虽然这个框架很小,但是包含了ORM,IOC,AOP以及Restful service支持。真所谓麻雀虽小,但是五脏俱全。今天主要讲解的就是基于CodeFirst的ORM实现方式。
在传统的开发思维中,我们一般都是先建立好数据库,然后布局各种Model类,最后调用。这种方式被称为DbFirst方式,也就是先有DataBase,然后再布局逻辑。而CodeFirst相反,是先建立好model,建立好需要的字段,然后由EntityFramework来自动生成数据库的表,看上去有点像DDD的开发方式。
下面就开始吧。
实现步骤解说
首先,我们以一个简易的图书借阅为例:在图书馆中,图书是有分类的,比如属于计算机类,还是属于文学类;图书是有存放位置的,比如存放于图书馆一楼,还是二楼;图书是有自身属性的,比如图书名称,图书作者等;图书借阅是需要人来参与的,所以会有学生这个集体;图书借阅需要知道谁借了什么书,什么时候到期等,是需要一个数据存储中心的。所以,综上所述,可以建立如下的Model来。
来看看数据关系图:

这里可以看到总共有五张表,他们的Model类创建如下:
Book实体类,主要用来描述图书的本身属性,一本书只能放置在一个地方,只能属于一个种类,有BookTypeID和BookPlaceID作为外键约束:
1: namespace BookStore.Data
2: {
3: public class Book
4: {
5: public Book()
6: {
7: BookType = new BookType();
8: BookPlace = new BookPlace();
9: }
10:
11: public int ID { get; set; }
12: public string Name { get; set; }
13: public string Author { get; set; }
14: public string Publishment { get; set; }
15: public int BookTypeID { get; set; }
16: public int BookPlaceID { get; set; }
17:
18: public BookType BookType { get; set; }
19: public BookPlace BookPlace { get; set; }
20: }
21: }
BookLend实体类,主要用来描述哪位学生借阅了什么书籍,一个学生可以借阅多本书籍,所以里面放了一个Student实体类,对应着多个Books,有BookID和StudentID作为外键约束:
1: namespace BookStore.Data
2: {
3: public class BookLend
4: {
5: public BookLend()
6: {
7: Student = new Student();
8: Books = new List<Book>();
9: }
10: public int ID { get; set; }
11: public int LendDays { get; set; }
12: public DateTime LendDate { get; set; }
13: public int BookID { get; set; }
14: public int StudentID { get; set; }
15:
16: public IList<Book> Books { get; set; }
17: public Student Student { get; set; }
18: }
19: }
BookPlace实体类,主要用来描述图书放置的位置:
1: namespace BookStore.Data
2: {
3: public class BookPlace
4: {
5: public int ID { get; set; }
6: public string Position { get; set; }
7: }
8: }
BookType实体类,主要用来描述图书种类:
1: namespace BookStore.Data
2: {
3: public class BookType
4: {
5: public int ID { get; set; }
6: public string Name { get; set; }
7: }
8: }
Student实体类,主要用来描述学生属性:
1: namespace BookStore.Data
2: {
3: public class Student
4: {
5: public int ID { get; set; }
6: public string Name { get; set; }
7: public string Number { get; set; }
8: public string Major { get; set; }
9: public string TelPhone { get; set; }
10: public string Address { get; set; }
11: public Gender Gender { get; set; }
12: }
13: }
这里还有个附加的枚举性别选项:
1: namespace BookStore.Data
2: {
3: public enum Gender
4: {
5: Male = 0, //男
6: Female = 1 //女
7: }
8: }
到这里,我们的Model就创建好了。
然后我们来创建ModelMapper。这种Mapper主要是用来设置各个字段的属性的。
BookMapper类:
1: namespace BookStore.Data
2: {
3: public class BookMapper:EntityTypeConfiguration<Book>
4: {
5: public BookMapper()
6: {
7: this.ToTable("Book");
8:
9: this.HasKey(c => c.ID);
10: this.Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
11: this.Property(c => c.ID).IsRequired();
12:
13: this.Property(c => c.Name).HasMaxLength(255);
14: this.Property(c => c.Name).IsRequired();
15:
16: this.Property(c => c.Author).HasMaxLength(255);
17: this.Property(c => c.Author).IsOptional();
18:
19: this.Property(c => c.Publishment).HasMaxLength(255);
20: this.Property(c => c.Publishment).IsRequired();
21:
22: this.HasRequired(c => c.BookType).WithMany().HasForeignKey(s => s.BookTypeID);
23: this.HasRequired(c => c.BookPlace).WithMany().HasForeignKey(s => s.BookPlaceID);
24:
25: }
26: }
27: }
第7行代码表示:对于Book实体类来说,最终将会在数据库中为其创建名称为Book的数据表。
第9行代码表示:这是一个主键。
第10行代码表示:这个主键是自增的。
第11行代码表示:这个主键是不能为空的。
第13,14行代码表示:这是一个普通属性,字段最大长度为255,不能为空。
第16,17行代码表示:这是一个普通属性,字段最大长度为255,可以为空。
第22,23行代码表示:在BookType表和BookPlace表中存在外键依赖。需要注意的是,如果Model类中定义了BookTypeID和BookPlaceID,这里一定要用HasForeignKey方法来指明。否则,可以利用Map方法来隐式指定。
接下来的Mapper就不一一解释了:
BookLendManager类:
1: namespace BookStore.Data
2: {
3: public class BookLendMapper : EntityTypeConfiguration<BookLend>
4: {
5: public BookLendMapper()
6: {
7: this.ToTable("BookLend");
8:
9: this.HasKey(c=>c.ID);
10: this.Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
11: this.Property(c => c.ID).IsRequired();
12:
13: this.Property(c => c.LendDays).IsRequired();
14:
15: this.Property(c => c.LendDate).IsRequired();
16: this.Property(s => s.LendDate).HasColumnType("smalldatetime");
17:
18: this.HasRequired(c => c.Books).WithMany().HasForeignKey(s=>s.BookID);
19: this.HasRequired(c => c.Student).WithMany().HasForeignKey(s =>s.StudentID);
20: }
21: }
22: }
BookPlaceMapper类:
1: namespace BookStore.Data
2: {
3: public class BookPlaceMapper : EntityTypeConfiguration<BookPlace>
4: {
5: public BookPlaceMapper()
6: {
7: this.ToTable("BookPlace");
8:
9: this.HasKey(c=>c.ID);
10: this.Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
11: this.Property(c => c.ID).IsRequired();
12:
13: this.Property(c => c.Position).IsRequired();
14: this.Property(c => c.Position).HasMaxLength(255);
15: }
16: }
17: }
BookTypeMapper类:
1: namespace BookStore.Data.Mapper
2: {
3: public class BookTypeMapper : EntityTypeConfiguration<BookType>
4: {
5: public BookTypeMapper()
6: {
7: this.ToTable("BookType");
8:
9: this.HasKey(c => c.ID);
10: this.Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
11: this.Property(c => c.ID).IsRequired();
12:
13: this.Property(c => c.Name).IsRequired();
14: this.Property(c => c.Name).HasMaxLength(255);
15: }
16: }
17: }
StudentMapper类:
1: namespace BookStore.Data
2: {
3: public class StudentMapper : EntityTypeConfiguration<Student>
4: {
5: public StudentMapper()
6: {
7: this.ToTable("Student");
8:
9: this.HasKey(c=>c.ID);
10: this.Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
11: this.Property(c => c.ID).IsRequired();
12:
13: this.Property(c => c.Name).IsRequired();
14: this.Property(c => c.Name).HasMaxLength(255);
15:
16: this.Property(c => c.Number).IsRequired();
17: this.Property(c => c.Number).HasMaxLength(12);
18:
19: this.Property(c => c.Major).IsOptional();
20: this.Property(c => c.Major).HasMaxLength(255);
21:
22: this.Property(c => c.Address).IsOptional();
23: this.Property(c => c.Address).HasMaxLength(255);
24:
25: this.Property(c => c.Gender).IsRequired();
26: }
27: }
28: }
当我们写完这些mapper的时候,工作已经完成一大半了,剩下的就是如何将其自动创建到数据库中的问题了。
这里我们需要用到EF的SetInitializer方法:
首先创建一个BookContext,继承自DbContext类,然后在构造中书写以下代码,以便实现数据实体类迁移:
1: public BookContext()
2: : base("BookConnection")
3: {
4: Configuration.ProxyCreationEnabled = false;
5: Configuration.LazyLoadingEnabled = false;
6: Database.SetInitializer(new MigrateDatabaseToLatestVersion<BookContext, BookContextMConfig>());
7: }
1: protected override void OnModelCreating(DbModelBuilder modelBuilder)
2: {
3: modelBuilder.Configurations.Add(new BookMapper());
4: modelBuilder.Configurations.Add(new BookLendMapper());
5: modelBuilder.Configurations.Add(new BookTypeMapper());
6: modelBuilder.Configurations.Add(new BookPlaceMapper());
7: modelBuilder.Configurations.Add(new StudentMapper());
8: modelBuilder.Configurations.Add(new ManagerMapper());
9: base.OnModelCreating(modelBuilder);
10: }
其中需要注意BookContextMConfig这个类,它需要继承DbMigrationsConfiguration类:
1: public class BookContextMConfig : DbMigrationsConfiguration<BookContext>
2: {
3: public BookContextMConfig()
4: {
5: this.AutomaticMigrationDataLossAllowed = true;
6: this.AutomaticMigrationsEnabled = true;
7: }
8: }
这样我们的一个完整的ORM就封装好了.通过访问BookContext对象,我们就可以从数据库获得与之对应的实体类.
最后还要注意,需要将数据库连接写到配置文件中:
<connectionStrings>
<add name="BookConnection" connectionString="server=180-server;database=BookConnection;uid=sa;pwd=*****" providerName="System.Data.SqlClient" />
</connectionStrings>
当这个实例运行起来的时候,我们就可以看到数据库中的表被自动创建了.并且实例化BookContext对象之后,我们可以获取到所有的Books,Students,BookTypes,BookPlaces,BookLends。
下一节主要来说明如何进行IOC注入。
TinyFrame开篇:基于CodeFirst的ORM的更多相关文章
- Atitit 基于meta的orm,提升加速数据库相关应用的开发
Atitit 基于meta的orm,提升加速数据库相关应用的开发 1.1. Overview概论1 1.2. Function & Feature功能特性1 1.2.1. meta api2 ...
- [simple-orm-mybaits]基于Mybatis的ORM封装介绍
目录 前言 ORM框架现状 Mybatis优缺点 simple-orm-mybatis设计思路介绍 simple-orm-mybatis使用说明 simple-orm-mybatis实际使用 推荐最佳 ...
- 一个基于注解的orm简单实现(二):实现思路
先来看一段常见的数据库操作代码: ``` protected User getDataFromDatabase(long id){ String sql = "select firstnam ...
- ODB——基于c++的ORM映射框架尝试(使用)
摘要: 2.使用 首先,需要定义一个对象,用来和数据库字段对应: [cce lang=”cpp”] #ifndef VOLUME_H #define VOLUME_H #include #includ ...
- 基于对象的orm跨表查询再练习
model.py from django.db import models # Create your models here. class Book(models.Model): nid = mod ...
- TinyFrame系列:基于EFCodeFirst,IOC,AOP的轻型框架
TinyFrame开篇:基于CodeFirst的ORM TinyFrame续篇:整合Spring IOC实现依赖注入 TinyFrame再续篇:整合Spring AOP实现日志拦截 TinyFrame ...
- TinyFrame续篇:整合Spring IOC实现依赖注入
上一篇主要讲解了如何搭建基于CodeFirst的ORM,并且在章节末我们获取了上下文对象的实例:BookContext.这节主要承接上一篇,来讲解如何整合Spring IOC容器实现控制反转,依赖注入 ...
- 基于GTK+3 开发远程控制管理软件(C语言实现)系列 一 开篇
近期趁公司没项目来,想学习一下C和GTK+3 ,顺道再学习一下Linux下有关网络编程方面的知识. 一.学习知识: 1.C基本语法 2.GTK+3 API学习 GUI相关知识学习 3.Glade使用及 ...
- 基于abp框架的数据库种子数据初始化
目录 基于abp框架的数据库种子数据初始化 1.背景 2.参照 3.解决方案 3.1 初始化数据 3.2 依赖注入方法容器里获取数据库上下文 3.3 封装创建初始化数据列表方法 3.4 数据库中没有的 ...
随机推荐
- laravel excel迁移到lumen
1.简介 Laravel Excel 在 Laravel 5 中集成 PHPOffice 套件中的 PHPExcel ,从而方便我们以优雅的.富有表现力的代码实现Excel/CSV文件的导入和 导出 ...
- input 默认值为灰色,输入时清楚默认值
input 默认值为灰色,输入时清楚默认值 <input value="please input your name" onFocus="if(value==def ...
- w3wp.exe(IIS ) CPU 占用 100% 的常见原因及解决办法
对于IIS 管理员来说,经常会碰到 Web 服务器 CPU 占用 100% 的情况,以下是个人的日常工作总结和一些解决办法,主要用来剖析 w3wp.exe(IIS ) 占用 CPU 100% 的一些 ...
- Protocol 编码的三种常用方式
1.使用固定长度 2.使用固定长度的请求头,请求头中说明了body的长度. 例如HTTP 协议: http请求协议: http 响应协议: 3.使用界定符.例如有很多基于text(文本)协议都会在每个 ...
- [转]CentOS 6.4下PXE+Kickstart无人值守安装操作系统
一.简介 1.1 什么是PXE PXE(Pre-boot Execution Environment,预启动执行环境)是由Intel公司开发的最新技术,工作于Client/Server的网络模式,支持 ...
- SQL Server开发接口生成方法
为提高开发效率,生成固定格式的接口是必须的,以下以提供新增/修改/删除/读取接口为例: 以常见的表结构为例,特殊表结构可自己尝试去调整方法 主要通过系视图 sys.columns生成方法:为包含列的对 ...
- python 缩进语法,优缺点
Python的语法比较简单——采用缩进方式 缩进有利有弊: 好处之一是强迫你写出格式化的代码,但没有规定缩进是几个空格还是Tab.按照约定俗成的管理,应该始终坚持使用4个空格的缩进. 其二是强迫你写出 ...
- 【OpenWRT之旅】如何自定义一个配置文件的设置界面
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1. 引言 OpenWRT中采用LuCI作为它的Web interface界面框架,采用Lua语言.在本文中将以 ...
- .Net程序员之Python基础教程学习----函数和异常处理[Fifth Day]
今天主要记录,Python中函数的使用以及异常处理. 一.函数: 1.函数的创建以及调用. def Add(val1,val2): return val1+val2; print Add( ...
- Eclipse调试Bug的七种常用技巧
1. 条件断点 断点大家都比较熟悉,在Eclipse Java 编辑区的行头双击就会得到一个断点,代码会运行到此处时停止. 条件断点,顾名思义就是一个有一定条件的断点,只有满足了用户设置的条件,代码才 ...