前言

做项目的这段时间,由于比较忙,一直没有机会闲下来思考。正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做: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:          }
然后重写其OnModelCreating方法,将Mapper类加入到ModelBuilder中:
   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的更多相关文章

  1. Atitit  基于meta的orm,提升加速数据库相关应用的开发

    Atitit  基于meta的orm,提升加速数据库相关应用的开发 1.1. Overview概论1 1.2. Function & Feature功能特性1 1.2.1. meta api2 ...

  2. [simple-orm-mybaits]基于Mybatis的ORM封装介绍

    目录 前言 ORM框架现状 Mybatis优缺点 simple-orm-mybatis设计思路介绍 simple-orm-mybatis使用说明 simple-orm-mybatis实际使用 推荐最佳 ...

  3. 一个基于注解的orm简单实现(二):实现思路

    先来看一段常见的数据库操作代码: ``` protected User getDataFromDatabase(long id){ String sql = "select firstnam ...

  4. ODB——基于c++的ORM映射框架尝试(使用)

    摘要: 2.使用 首先,需要定义一个对象,用来和数据库字段对应: [cce lang=”cpp”] #ifndef VOLUME_H #define VOLUME_H #include #includ ...

  5. 基于对象的orm跨表查询再练习

    model.py from django.db import models # Create your models here. class Book(models.Model): nid = mod ...

  6. TinyFrame系列:基于EFCodeFirst,IOC,AOP的轻型框架

    TinyFrame开篇:基于CodeFirst的ORM TinyFrame续篇:整合Spring IOC实现依赖注入 TinyFrame再续篇:整合Spring AOP实现日志拦截 TinyFrame ...

  7. TinyFrame续篇:整合Spring IOC实现依赖注入

    上一篇主要讲解了如何搭建基于CodeFirst的ORM,并且在章节末我们获取了上下文对象的实例:BookContext.这节主要承接上一篇,来讲解如何整合Spring IOC容器实现控制反转,依赖注入 ...

  8. 基于GTK+3 开发远程控制管理软件(C语言实现)系列 一 开篇

    近期趁公司没项目来,想学习一下C和GTK+3 ,顺道再学习一下Linux下有关网络编程方面的知识. 一.学习知识: 1.C基本语法 2.GTK+3 API学习 GUI相关知识学习 3.Glade使用及 ...

  9. 基于abp框架的数据库种子数据初始化

    目录 基于abp框架的数据库种子数据初始化 1.背景 2.参照 3.解决方案 3.1 初始化数据 3.2 依赖注入方法容器里获取数据库上下文 3.3 封装创建初始化数据列表方法 3.4 数据库中没有的 ...

随机推荐

  1. Azure File

    Azure File 服务使用标准 SMB 2.1 协议提供文件共享.Azure 中运行的应用程序现在可以使用熟悉的标准文件系统 API(如 ReadFile 和 WriteFile)在虚拟机之间轻松 ...

  2. 网络编程4--毕向东java基础教程视频学习笔记

    Day24 06 自定义浏览器-Tomcat服务端07 自定义图形界面浏览器-Tomcat服务端08 URL-URLConnection09 小知识点10 域名解析 06 自定义浏览器-Tomcat服 ...

  3. Java Gradle入门指南之gretty插件(安装、命令与核心特性)

        Java Web应用开发时常使用Gradle来进行项目管理,可以十分便利地解决包依赖等问题.war插件的出现,让项目部署成为一个复制粘贴的过程,那有没有办法让Java web应用的部署,就像w ...

  4. 编写可测试的JavaScript代码

    <编写可测试的JavaScript代码>基本信息作者: [美] Mark Ethan Trostler 托斯勒 著 译者: 徐涛出版社:人民邮电出版社ISBN:9787115373373上 ...

  5. [MySQL Reference Manual] 4 MYSQL Program

    4 MYSQL Program 目录 4 MYSQL Program 4.3 MySQL Server和Server启动程序 4.3.1 mysqld 4.3.2 mysqld_safe 4.3.3 ...

  6. [Linux 性能检测工具]SAR

    SAR NAME: SAR报告,收集,保存系统活动信息 语法: sar  [ -A ] [ -b ] [ -B ] [ -C ] [ -d ] [ -h ] [ -i interval ] [ -m ...

  7. 高效coder,筹备开源框架toutou.escort.js

    背景:JavaScript在工作中运用的非常广泛,作为一门弱类型语言,在使用JavaScript的时候,很多事情需要coder manual的去完成,这无疑增加了coder的工作量. 扩展:在这样的背 ...

  8. android viewpager 图片翻页例子

    使用ViewPager这个类可以轻松实现多个页面的滑动功能 viewpager默认在工具界面上是找不到的,需求添加android-support-v4.jar包: 如果没有找到,需要打开Android ...

  9. WebRequest 访问 https

    参考代码: 1: [TestMethod] 2: public void TestHttps() 3: { 4: var req =(HttpWebRequest) System.Net.WebReq ...

  10. WPF自定义空心文字

    首先创建一个自定义控件,继承自FrameworkElement,“Generic.xaml”中可以不添加样式. 要自定义空心文字,要用到绘制格式化文本FormattedText类.FormattedT ...