第05章 EntityFramework6:Code Frist实体关系设计--迁移数据库--初始化数据

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可以在配置文件中来决定是否迁移.

        本章重点是迁移初步认知,其次体会多对多关系实体设计(个人觉得这种关系比较扯淡)!

       (注:对于留言的内容是交流,询问,反馈,我尽量回复。对随意而感的话题,抱歉我不回复!真心期待大家多多支持我!)

  

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。