使用ASP.NET WEB API构建基于REST风格的服务实战系列教程(一)——使用EF6构建数据库及模型
原文:使用ASP.NET WEB API构建基于REST风格的服务实战系列教程(一)——使用EF6构建数据库及模型

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html

使用Entity Framework Code First模式构建数据库对象

已经决定使用EF CodeFirst来创建数据库了,因此我们使用POCO类(“Plain Old CLR Objects)来定义我们的Model。我们通过写标准的.NET类来定义适合我们API的领域模型。那些POCO类就会为我们创建数据库。

我们的培训系统数据库比较简单,首先我们需要有学生”Students”,导师”Tutors”,除此之外我们还需要定义课程”Courses”以及科目”Subjects”。在我们的系统中,我们允许每个学生去报名参加不同的课程

下图是我们数据库建立后的结果,我在这里列出来的目的是为了帮助大家更好的理解接下来创建的POCO类(图不是很清晰,凑合看吧):

第一步:创建一个空的类库项目

打开VS,创建一个空的类库项目

.NET Framewok版本的话我用的事4.5的,选4.0的也行

第二步:使用NuGet添加Entity Framework的引用

右击引用->管理NuGet程序包->右上角输入Entity Framework,选择安装。装好之后就应该是这么一个样子:

这里用的是Entity Framework6,因为这个版本支持了枚举类型,在这次的项目里也有涉及

第三步:创建Model

前面已经说了,到目前为止我们还没有数据库。因此我们需要写标准的.NET类来定义领域模型并帮我们生成数据库

新建一个Entities文件夹并创建5个类(“Student”,“Course”,“Subject”,“Tutor”,“Enrollment”),这几个简单的实体类将为我们创建数据库

public class Course{public Course(){Enrollments = new List<Enrollment>();CourseTutor = new Tutor();CourseSubject = new Subject();}public int Id { get; set; }public string Name { get; set; }public Double Duration { get; set; }public string Description { get; set; }public Tutor CourseTutor { get; set; }public Subject CourseSubject { get; set; }public ICollection<Enrollment> Enrollments { get; set; }}public class Enrollment{public Enrollment(){Student = new Student();Course = new Course();}public int Id { get; set; }public DateTime EnrollmentDate { get; set; }public Student Student { get; set; }public Course Course { get; set; }}public class Student{public Student(){Enrollments = new List<Enrollment>();}public int Id { get; set; }public string Email { get; set; }public string UserName { get; set; }public string Password { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public Gender Gender { get; set; }public DateTime DateOfBirth { get; set; }public DateTime? RegistrationDate { get; set; }public DateTime? LastLoginDate { get; set; }public ICollection<Enrollment> Enrollments { get; set; }}public class Subject{public Subject(){Courses = new List<Course>();}public int Id { get; set; }public string Name { get; set; }public ICollection<Course> Courses;}public class Tutor{public Tutor(){Courses = new List<Course>();}public int Id { get; set; }public string Email { get; set; }public string UserName { get; set; }public string Password { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public Gender Gender { get; set; }public ICollection<Course> Courses;}

不难发现,上面我们创建的Model并没有从任何基类继承,也没有打任何attributes。有哪些标准的话会使我们的数据访问拥有更好的延展性,这样的话我们就可以专心地去处理业务而不用过多地考虑数据的持久化。

Entity framework Code First默认使用一种叫“约定大于配置”的方式来为我们创建数据库(通过POCO类映射数据库的表,字段的数据类型,外键等)。在一些简单的应用程序中来说是非常好用的。但在我们的项目中将使用Fluent API配置我们自定义的数据库生成规则——“配置覆盖约定”

第四步:应用自定义映射规则

当我们决定使用配置来覆盖默认规则时,我们可以为每张表的字段配置数据类型,是否可空,表与表之间外键关系,主键以及标识列等等。

于是乎我们创建一个“Mappers”文件夹,新建5个继承自System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<T>的类。分别命名为: “CourseMapper”, “EnrollmentMapper”, “StudentMapper”, “SubjectMapper”, and “TutorMapper”

class CourseMapper : EntityTypeConfiguration<Course>{public CourseMapper(){this.ToTable("Courses");this.HasKey(c => c.Id);this.Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);this.Property(c => c.Id).IsRequired();this.Property(c => c.Name).IsRequired();this.Property(c => c.Name).HasMaxLength(255);this.Property(c => c.Duration).IsRequired();this.Property(c => c.Description).IsOptional();this.Property(c => c.Description).HasMaxLength(1000);this.HasRequired(c => c.CourseSubject).WithMany().Map(s => s.MapKey("SubjectID"));this.HasRequired(c => c.CourseTutor).WithMany().Map(t => t.MapKey("TutorID"));}}class EnrollmentMapper : EntityTypeConfiguration<Enrollment>{public EnrollmentMapper(){this.ToTable("Enrollments");this.HasKey(e => e.Id);this.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);this.Property(e => e.Id).IsRequired();this.Property(e => e.EnrollmentDate).IsRequired();this.Property(e => e.EnrollmentDate).HasColumnType("smalldatetime");this.HasOptional(e => e.Student).WithMany(e => e.Enrollments).Map(s => s.MapKey("StudentID")).WillCascadeOnDelete(false);this.HasOptional(e => e.Course).WithMany(e => e.Enrollments).Map(c => c.MapKey("CourseID")).WillCascadeOnDelete(false);}}class StudentMapper : EntityTypeConfiguration<Student>{public StudentMapper(){this.ToTable("Students");this.HasKey(s => s.Id);this.Property(s => s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);this.Property(s => s.Id).IsRequired();this.Property(s => s.Email).IsRequired();this.Property(s => s.Email).HasMaxLength(255);this.Property(s => s.Email).IsUnicode(false);this.Property(s => s.UserName).IsRequired();this.Property(s => s.UserName).HasMaxLength(50);this.Property(s => s.UserName).IsUnicode(false);this.Property(s => s.Password).IsRequired();this.Property(s => s.Password).HasMaxLength(255);this.Property(s => s.FirstName).IsRequired();this.Property(s => s.FirstName).HasMaxLength(50);this.Property(s => s.LastName).IsRequired();this.Property(s => s.LastName).HasMaxLength(50);this.Property(s => s.Gender).IsOptional();this.Property(s => s.DateOfBirth).IsRequired();this.Property(s => s.DateOfBirth).HasColumnType("smalldatetime");this.Property(s => s.RegistrationDate).IsOptional();this.Property(s => s.RegistrationDate).HasColumnType("smalldatetime");this.Property(s => s.LastLoginDate).IsOptional();this.Property(s => s.LastLoginDate).HasColumnType("smalldatetime");}}class SubjectMapper : EntityTypeConfiguration<Subject>{public SubjectMapper(){this.ToTable("Subjects");this.HasKey(s => s.Id);this.Property(s => s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);this.Property(s => s.Id).IsRequired();this.Property(s => s.Name).IsRequired();this.Property(s => s.Name).HasMaxLength(255);}}class TutorMapper : EntityTypeConfiguration<Tutor>{public TutorMapper(){this.ToTable("Tutors");this.HasKey(s => s.Id);this.Property(s => s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);this.Property(s => s.Id).IsRequired();this.Property(s => s.Email).IsRequired();this.Property(s => s.Email).HasMaxLength(255);this.Property(s => s.Email).IsUnicode(false);this.Property(s => s.UserName).IsRequired();this.Property(s => s.UserName).HasMaxLength(50);this.Property(s => s.UserName).IsUnicode(false);this.Property(s => s.Password).IsRequired();this.Property(s => s.Password).HasMaxLength(255);this.Property(s => s.FirstName).IsRequired();this.Property(s => s.FirstName).HasMaxLength(50);this.Property(s => s.LastName).IsRequired();this.Property(s => s.LastName).HasMaxLength(50);this.Property(s => s.Gender).IsOptional();}}

看看上面的代码,不难发现我们为每个POCO类属性(数据类型,是否为空,主键标识,外键关系)都做了配置。这些配置最终会影响我们数据库中表的创建。

关于具体Fluent API的配置方法,可以参考:http://www.cnblogs.com/hyl8218/archive/2011/10/10/2205240.html

第五步:创建Context类来实现数据持久化

现在我们要创建一个LearningContext类继承自System.Data.Entity.DbContext:

public class LearningContext : DbContext{public LearningContext() :base("eLearningConnection"){Configuration.ProxyCreationEnabled = false;Configuration.LazyLoadingEnabled = false;Database.SetInitializer(new MigrateDatabaseToLatestVersion<LearningContext, LearningContextMigrationConfiguration>());}public DbSet<Course> Courses { get; set; }public DbSet<Enrollment> Enrollments { get; set; }public DbSet<Student> Students { get; set; }public DbSet<Subject> Subjects { get; set; }public DbSet<Tutor> Tutors { get; set; }protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Configurations.Add(new StudentMapper());modelBuilder.Configurations.Add(new SubjectMapper());modelBuilder.Configurations.Add(new TutorMapper());modelBuilder.Configurations.Add(new CourseMapper());modelBuilder.Configurations.Add(new EnrollmentMapper());base.OnModelCreating(modelBuilder);}}

这个LearningContext类主要有三大任务

1.把我们定义的POCO类作为DBSet的属性对外公开,这意味着每一个POCO类都将被转化为数据库中的表

2.重写OnModelCreating方法将我们为POCO类自定义的映射规则添加到DbModelBuilder配置中

3.在LearningContext的构造函数中我们做了2件事:

(1)将ProxyCreationEnabled和LazyLoadingEnabled 2个属性设为false(默认都是true)。延迟加载(LazyLoading)主要是指当对象间的关联配置成导航属性暴露给外界的时候,那么这个属性的会在用到它的时候(在前台foreach的时候)才加载,那么极有可能成为性能杀手,我们项目中希望立即加载。而ProxyCreation是配合LazyLoading一起用的,因此当我们把这两个属性值设为false时,那么“LearningContext”就不会去加载导航属性除非调用了“Include”方法(下一章会有演示)。

(2)为数据库配置初始化和迁移策略,如果模型的属性被改变(添加了新的属性),就把数据库迁移到最新版本。为了实现这个功能,我们新建一个类LearningContextMigrationConfiguration继承自System.Data.Entity.Migrations.DbMigrationsConfiguration<TContext>

class LearningContextMigrationConfiguration : DbMigrationsConfiguration<LearningContext>{public LearningContextMigrationConfiguration(){this.AutomaticMigrationsEnabled = true;this.AutomaticMigrationDataLossAllowed = true;}#if DEBUGprotected override void Seed(LearningContext context){new LearningDataSeeder(context).Seed();}
#endif}

LearningContextMigrationConfiguration这个类主要有2个任务:

(1)在构造函数中,我们设置AutomaticMigrationsEnabled 属性为true,那么就意味着EF会为我们自动迁移数据库而不考虑版本问题。同时我们把AutomaticMigrationDataLossAllowed属性也设为true但这样做在开发环境中是很危险的,因为如果这个属性设为false时,一旦数据库在自动迁移时发生数据丢失,那么就会抛出一个异常。但在这次的系列中我们确保没问题。

(2)重写Seed方法来为我们的数据库添加初始数据,这个函数在我们应用程序每次启动时执行。“LearningDataSeeder”这个类主要用于提供需要的数据,具体代码在本章结束时提供。

本章总结

到目前为止,我们已经把用于创建数据库的Model和配置都实现了。在这个时候我们应该想一想:数据访问层是否已经完成?当我们使用Web Api操作的时候是否方便 快捷 高效?我们是否应该对已有的数据访问层再做一次封装?。。。 因此下一章我们将使用“Repository”模式应用在我们的项目中。

随堂代码:http://yun.baidu.com/share/link?shareid=1763536438&uk=17559114

posted on 2014-02-23 14:41 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/3561921.html

使用ASP.NET WEB API构建基于REST风格的服务实战系列教程(一)——使用EF6构建数据库及模型...相关推荐

  1. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程

    最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tuto ...

  2. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【十】——使用CacheCow和ETag缓存资源...

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 本文将使用一个开源框架CacheCow来实现针对Http请求资源缓存,本文主要介绍服务器端的 ...

  3. ASP.NET Web Api 教程

    使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[七]--实现资源的分页 摘要: 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.h ...

  4. 我对 ASP.NET Web API 的随想

    其实自己实现一个类似与 ASP.NET Web API 的轻量级 Web 服务(PS:不是说 Web Service 技术)也不是很难的事,就算不用 ASP.NET MVC,用 ASP.ASP.NET ...

  5. Asp.net Web Api开发 性能:使用Jil提升Json序列化性能

    from:http://blog.csdn.net/sqqyq/article/details/51692342 看了几篇网上关于各种序列化工具的性能对比,在这里再粘贴下: 我们使用了ASP.NET ...

  6. Asp.net Web Api开发(第二篇)性能:使用Jil提升Json序列化性能

    看了几篇网上关于各种序列化工具的性能对比,在这里再粘贴下: 我们使用了ASP.NET WEB API来提供RESTfull风格的接口给APP调用,默认序列化库用的是:Newtonsoft.Json 为 ...

  7. ASP.NET Web API与Owin OAuth:使用Access Toke调用受保护的API(二)

    在前一篇博文中,我们使用OAuth的Client Credential Grant授权方式,在服务端通过CNBlogsAuthorizationServerProvider(Authorization ...

  8. ASP.NET Web API与Owin OAuth:使用Access Toke调用受保护的API

    在前一篇博文中,我们使用OAuth的Client Credential Grant授权方式,在服务端通过CNBlogsAuthorizationServerProvider(Authorization ...

  9. ASP.NET Web API 接口执行时间监控

    软件产品常常会出现这样的情况:产品性能因某些无法预料的瓶颈而受到干扰,导致程序的处理效率降低,性能得不到充分的发挥.如何快速有效地找到软件产品的性能瓶颈,则是我们感兴趣的内容之一. 在本文中,我将解释 ...

  10. 【转】在ASP.NET Web API 2中使用Owin基于Token令牌的身份验证

    基于令牌的身份验证 基于令牌的身份验证主要区别于以前常用的基于cookie的身份验证,基于cookie的身份验证在B/S架构中使用比较多,但是在Web Api中因其特殊性,基于cookie的身份验证已 ...

最新文章

  1. MySQL如何快速插入数据
  2. 8.使用Xshell5密钥登录liunx
  3. lintcode:二叉树的中序遍历
  4. Linux系统中,read文件过程分析
  5. vue部署到服务器 接口调用不了_Python 调用 Azure API 实现服务器自动部署
  6. JavaScript-引入JavaScript
  7. 阅读笔记11-孤独后厂村:30万互联网人跳不出的中国硅谷
  8. 微软推出面向 Kubernetes 的 OSM 项目,计划捐赠给 CNCF 基金会
  9. 剪切板是计算机系统,剪贴板
  10. power designer mysql_powerdesigner下载
  11. Python 使用OpenCV计算机视觉(一篇文章从零毕业)【附带OCR文字识别项目、停车场车位智能识别项目】
  12. bi 工具 市场排行榜_国产移动BI工具排名
  13. 零售版:GameMaker Studio Ultimate 2022.8.X
  14. 全息投影是计算机技术吗,全息投影、VR技术、AR增强现实技术的区别
  15. xgboost自定义损失函数评估函数
  16. 2019年胡润百富榜发布,比特大陆创始人詹克团成「中国区块链首富」!
  17. Logi-KafkaManager安装
  18. 小白学习Linux命令
  19. win10系统启动多了onekeyGhost 或者 其他 系统,如何删除
  20. 《囧妈》口碑扑街?Python告诉你观众这次为何不买账了

热门文章

  1. 去除A和B数组中的交集
  2. YUM安装部署LAMP环境
  3. 行尸走肉第八季/全集The Walking Dead迅雷下载
  4. ASP.NET FileUpload用法
  5. Asp.net 5种页面转向方法 转载
  6. 项目实战中的防御性编程
  7. 亲测ArcGis albers投影转换为经纬度的代码
  8. Android进阶(二) Activity调用Service 通过AIDL实现
  9. Luogu2564 [SCOI2009]生日礼物
  10. 小程序学习笔记(5)-目录结构介绍