前言

做项目的这段时间,由于比较忙,一直没有机会闲下来思考。正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做: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. 2.2 CMMI2级——项目计划(Project Planning)

    大家都明白这样的一个道理:做事情要有计划,有一个不成熟的计划总比没有计划要好,软件开发这么复杂的活动,更加需要计划.那么应该怎样做好一个计划呢? 如果对项目的范围.规模.性质.任务.工作量.费用等都不 ...

  2. MVC数据库数据分页显示

    首先从数据库获取数据 using System; using System.Collections.Generic; using System.Linq; using System.Web; usin ...

  3. C# 得到sqlserver 数据库存储过程,触发器,视图,函数 的定义

    经常从 生产环境 到测试环境, 需要重新弄一整套的数据库环境, 除了表结构以及表结构数据,可以用动软代码生成器 生成之外, 像 存储过程,触发器,等,好像没有批量操作的,意义哥哥农比较麻烦, 所以最近 ...

  4. Windows下好用到必须开机自启的小工具

    折腾过linux,黑苹果,最后还是回到了盖茨大叔的windows.得出的结论是,日常使用的话,折腾Linux还不如把精力去拿去折腾windows.分享下折腾的成果,介绍下一些很不错的小工具.     ...

  5. js相对路径相关(比如:js中的路径依赖导入该js文件的路径)

    问题描述: 前几天调用同事的js接口文件,在他自己的html测试页面ok,在我这边调用时出现问题. debug过程中,将该测试html移到其他位置都不行,放到原html测试页面同层次路径下是OK的. ...

  6. 烂泥:高负载均衡学习haproxy之关键词介绍

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 上一篇文章我们简单讲解了有关haproxy的安装与搭建,在这篇文章我们把haproxy配置文件中使用到的关键词一一介绍下. 关注我微信ilann ...

  7. EarthWarrior3D游戏ios源码

    这是一款不错的ios源码源码,EarthWarrior3D游戏源码, 并且游戏源代码支持多平台. 适用于cocos v2.1.0.0版本 源码下载:http://code.662p.com/view/ ...

  8. Web学习之css

    CSS指层叠样式表(Cascading Style Sheets),CSS 是标准的布局语言,用来控制元素的尺寸.颜色.排版.CSS 由 W3C 发明,用来取代基于表格的布局.框架以及其他非标准的表现 ...

  9. Object-C中self和super的区别

    self与super的区别 原文CSDN evilotus 有所整理 **** 在ObjC中的类实现中经常看到这两个关键字"self"和"super",以以前o ...

  10. WinCE项目应用之RM905a+活度计远程检定方法研究

    前文<RM905a+医用放射性核素活度计>中已经提到,基于WinCE5.0系统的RM905a+可以很方便的实现远程界面显示和控制.所以远程检定的主要工作在于服务器端的业务部分.基于< ...