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

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

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

时间: 2024-10-10 01:37:30

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

MyEclipse的实体关系设计

1. 可视化实体关系与ER图 MyEclipse ER-Designer帮助您直观地管理关系数据库,从设计生命周期,到实施.维护这一系列的过程.同时MyEclipse ER-Designer还提供现有数据库的可视化模型.因为ER-Designer的逆向工程数据库的实体 - 关系(ER)模型,所以在ER-Designer中利用数据库资源管理器的数据库连接器来访问数据库的元数据.由此看出ER-Designer渲染模型使用信息工程(IE)系统的ER来作为一个实体关系图(ERD).在任何时候,ER-De

.NET - EntityFramework 实体关系数据模型

EntityFramework 实体关系数据模型(DO.NET Entity Framework) ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案.该框架曾经为.NET Framework的一部分,但version 6之后从.NET Framework分离出来. 在项目中使用Entity Framework 要得到最高版本的Entity Framework 程序包,可以通过扩展与更新或者右击项目-引

Entity Framework 6 Recipes 2nd Edition(10-1)译-&gt;非Code Frist方式返回一个实体集合

存储过程 存储过程一直存在于任何一种关系型数据库中,如微软的SQL Server.存储过程是包含在数据库中的一些代码,通常为数据执行一些操作,它能为数据密集型计算提高性能,也能执行一些为业务逻辑. 当你使用数据的时候,有时你会通过存储过程来获取它们. 在本章, 我们探讨一些EF在使用存储过程时,需要关注的地方.我们在本书的其它章节也使用了存储过程, 但通常都是context为执行插入.更新和删除动作. 在本章,我们将为你展示多种使用存储过程的方式. 10-1. 非Code Frist方式返回一个

使用 EF Power Tool Code Frist 生成 Mysql 实体

原文:使用 EF Power Tool Code Frist 生成 Mysql 实体 1,在要生成的项目上右键   2,   3,   4,   5,  生成后的效果     已知问题: 1,在Mysql数据表中 tinyint(1) ,会被映射成为 C# bool ,这样造成一些数据信息的丢失. 这个问题应该是EF 工具的问题,暂时没有找到解决方案.      手工去修改生成的实体是不经济的,下次再更新时候,又会变成 bool型 .      所以解决的办法就是修改数据库字段型 ,一般情况下,

Entity Framework 实体框架的形成之旅--Code First的框架设计(5)

在前面几篇介绍了Entity Framework 实体框架的形成过程,整体框架主要是基于Database First的方式构建,也就是利用EDMX文件的映射关系,构建表与表之间的关系,这种模式弹性好,也可以利用图形化的设计器来设计表之间的关系,是开发项目较多采用的模式,不过问题还是这个XML太过复杂,因此有时候也想利用Code First模式构建整个框架.本文主要介绍利用Code First 来构建整个框架的过程以及碰到的问题探讨. 1.基于SqlServer的Code First模式 为了快速

从零开始,搭建博客系统MVC5+EF6搭建框架(1),EF Code frist、实现泛型数据仓储以及业务逻辑

前言      从上篇30岁找份程序员的工作(伪程序员的独白),文章开始,我说过我要用我自学的技术,来搭建一个博客系统,也希望大家给点意见,另外我很感谢博客园的各位朋友们,对我那篇算是自我阶段总结文章的评论,在里面能看出有很多种声音,有支持的我的朋友给我加油打气,有分享自己工作经历的朋友,有提出忠肯意见的朋友,有对记事本写代码吐槽的朋友,也有希望让我换个行业的,觉得我可能不适合这个行业朋友,不管怎样,我都接受,都是大家同行的一些忠告,谢谢大家. 首先我要在这里感谢很多博客园里面的大牛,写了很多系

第05章-可视化技术(4)

[译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934-23-8),由于时间关系,我们不能保证每周都能更新本书内容,但尽量做到一周更新一篇到两篇内容.敬请期待^_^.欢迎转载,另请转载时注明本文出处,谢谢合作!同时,由于译者水平有限,出错之处在所难免,欢迎指出订正!] [本小节内容对应原书的第112页至第117页] 5.3 规则网格可视化 规则网格在拓扑结构上规则

[Learn Android Studio 汉化教程]第四章 : Refactoring Code

[Learn Android Studio 汉化教程]第四章 : Refactoring Code 第四章 Refactoring Code    重构代码 在Android Studio中开发,解决方案不会总是一蹴而成的.作为一个有效率的编程者,在你的开发,调试和测试中需要一些弹性以及代码重构.随着在这章中的行进,你将明白Android Studio如何产生代码:在这章里你将看到Android Studio如何重构你的代码.重构代码最大的风险是可能引入不期望的错误.通过分析某些风险重构操作的结

EF6.0+APS.NET MVC5.0项目初探三(code first实体映射到数据库)

到这里架构就搭建完了,该向里面填充东西的时候了,如上篇:EF6.0+APS.NET MVC5.0项目初探二(类库引用关系及说明) 第一步 :在需要添加EF的类库Domain.DbContext上右击->管理NuGet程序包->找到Entity FrameWork下载安装. 如图: 第二步:新建DbContext 第三步:在类库Domain.Entity上添加引用System.ComponentModel.DataAnnotations(用于验证的引用) 并新建实体类. 1 using Syst