1.写作背景
在写这篇文章前,本想继续补充完前面介绍到WebApi知识点,但下面的讲解,要进行实体/模型设计,并对数据进行CRUD实际操作了,所以先介绍一下EF基本使用啦!
本章为何不以最新版的EF7(下一章也会介绍它)先讲?
一是EF7还处于beta阶段,功能也没有开发完毕,生产环境应用有诸多问题;
二是EF7想比之前的版本变化还是很多的,我们先从代码对比上了解,以便你以后从EF6升级到EF7;
三是EF6目前也不能在ASP.NET 5类型项目中使用,但它对ASP.NET 5以外的类型项目非常好用了,这个要给赞的。
本章对EF6前身后世,不做过多细述,我这次总结学习的系列写文章,毕竟是针对ASP.NET 5技术开展的。
2.创建项目
注:以下代码,在传统的web等项目类型中也是适用。但讲解以老版的控制台项目:
3.实体类
一对多关系: 角色Role:用户User=1:N
Role.cs代码:
using System.Collections.Generic; namespace EF6.Consoles.Models { /// <summary> /// 角色实体 /// </summary> public class Role { public int Id { get; set; } public string RoleName { get; set; } /// <summary> /// 用户实体集合 (导航属性) /// </summary> public ICollection<User> Users { get; set; } } }
User.cs代码:
namespace EF6.Consoles.Models { /// <summary> /// 用户实体 /// </summary> public class User { public int Id { get; set; } public string UserName { get; set; } public string Password { get; set; } /// <summary> /// 角色Id (外键) /// </summary> public int RoleId { get; set; } /// <summary> /// 角色实体 (导航属性) /// </summary> public Role Role { get; set; } } }
多对多关系:类别Category:产品Product=N:M
Category.cs代码:
using System.Collections.Generic; namespace EF6.Consoles.Models { /// <summary> /// 类别实体 /// </summary> public class Category { public int Id { get; set; } public string CategoryName { get; set; } /// <summary> /// 产品实体集合 (导航属性) /// </summary> public ICollection<Product> Products { get; set; } } }
Product.cs代码:
using System.Collections.Generic; namespace EF6.Consoles.Models { /// <summary> /// 产品实体 /// </summary> public class Product { public int Id { get; set; } public string ProductName { get; set; } /// <summary> /// 类别实体集合 (导航属性) /// </summary> public ICollection<Category> Categories { get; set; } } }
注:外键(含左右外键)可以为空的关系,就不举例了;其次实体属性(数据)特性注解在下一章EF7再说。实体配置还有Fluent API方式。
4.安装EF
5.数据库上下文
EFContext.cs代码:
using System.Data.Entity; using System.Data.Entity.ModelConfiguration.Conventions; namespace EF6.Consoles.Models { public class EFContext : DbContext { public EFContext() : base("EFContext") { } public DbSet<Role> Roles { get; set; } public DbSet<User> Users { get; set; } public DbSet<Category> Categories { get; set; } public DbSet<Product> Products { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //也可以不设置,也会默认 modelBuilder.Entity<Category>() .HasMany(c => c.Products).WithMany(p => p.Categories) .Map(t => t.MapLeftKey("CategoryId") .MapRightKey("ProductId") .ToTable("CategoryProduct")); } } }
6.数据库连接字符串
在App.config中<configuration>节点内添加数据库连接字符串:
<connectionStrings> <add name="EFContext" connectionString="Data Source=.;Initial Catalog=TestDB;UID=sa;PWD=123456" providerName="System.Data.SqlClient" /> </connectionStrings>
7.手动迁移
查看迁移帮助
启用迁移
此时生成目录及文件:
修改Configuration.cs代码:
using EF6.Consoles.Models; using System.Collections.Generic; using System.Data.Entity.Migrations; using System.Linq; namespace EF6.Consoles.Migrations { internal sealed class Configuration : DbMigrationsConfiguration<EFContext> { public Configuration() { AutomaticMigrationsEnabled = false; } protected override void Seed(EFContext db) { var roles = new List<Role> { new Role() { RoleName="管理员"}, new Role() { RoleName="会员"} }; roles.ForEach(list => db.Roles.AddOrUpdate(r => r.RoleName, list)); db.SaveChanges(); var users = new List<User> { new User() { UserName="givecase", Password="123", Role = db.Roles.Single(r => r.RoleName == "管理员")}, new User() { UserName="user01", Password="abc", Role = db.Roles.Single(r => r.RoleName == "会员")}, new User() { UserName="user02", Password="123456", Role = db.Roles.Single(r => r.RoleName == "会员")}, }; users.ForEach(list => db.Users.AddOrUpdate(u => u.UserName, list)); db.SaveChanges(); var products = new List<Product> { new Product() { ProductName="联想电脑" }, new Product() { ProductName="戴尔电脑" }, new Product() { ProductName="三星手机" }, new Product() { ProductName="苹果手机" }, new Product() { ProductName="苹果电脑" } }; products.ForEach(list => db.Products.AddOrUpdate(p => p.ProductName, list)); db.SaveChanges(); var categories = new List<Category> { new Category() {CategoryName="台式电脑",Products=new List<Product>() }, new Category() {CategoryName="笔记本电脑",Products=new List<Product>() }, new Category() {CategoryName="平板电脑",Products=new List<Product>() }, new Category() {CategoryName="4G手机",Products=new List<Product>() }, new Category() {CategoryName="3G手机",Products=new List<Product>() }, }; categories.ForEach(list => db.Categories.AddOrUpdate(c => c.CategoryName, list)); db.SaveChanges(); AddOrUpdateProduct(db, "台式电脑", "联想电脑"); AddOrUpdateProduct(db, "台式电脑", "戴尔电脑"); AddOrUpdateProduct(db, "平板电脑", "苹果电脑"); AddOrUpdateProduct(db, "4G手机", "苹果手机"); AddOrUpdateProduct(db, "4G手机", "三星手机"); AddOrUpdateProduct(db, "3G手机", "三星手机"); db.SaveChanges(); } void AddOrUpdateProduct(EFContext context, string categoryName, string productName) { var cat = context.Categories.SingleOrDefault(c => c.CategoryName == categoryName); var pro = cat.Products.SingleOrDefault(p => p.ProductName == productName); if (pro == null) { cat.Products.Add(context.Products.Single(p => p.ProductName == productName)); } } } }
添加迁移
更新数据库
OK!没有出错。
查看表关系图:
注:多对多关系,创建一个中间表CategoryProduct,查看其数据:
8.小结
预留问题: 以上迁移有什么不足之处?显然我们有时希望不用在nuget 控制台来执行,让程序在访问数据库时自动完成迁移。
方式:一是在程序代码中执行方法,可它也有一个缺点,那就是是否开启迁移,不是用App.config配置的;第二种方式,EF6可以在配置文件中来决定是否迁移.
本章重点是迁移初步认知,其次体会多对多关系实体设计(个人觉得这种关系比较扯淡)!
(注:对于留言的内容是交流,询问,反馈,我尽量回复。对随意而感的话题,抱歉我不回复!真心期待大家多多支持我!)