• EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作


    EF6 学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理)

    本篇参考原文地址:

    Creating an Entity Framework Data Model

    说明:学习笔记参考原文中的流程,为了增加实际操作性,并能够深入理解,部分地方根据实际情况做了一些调整;并且根据自己的理解做了一些扩展。

    本人的学习环境: VS2017 + EF 6.1.3 + .NET 4.6.1

    Step1 :  新建Web Application (我起名为EFTest)

    选择空白模板,但勾选 MVC 的Folder reference.

    Step2:  通过Package Manager Console来安装EF6

    Step3: 新建一个LocalDB的空的测试数据库

    Step4: 新建一个 主页面 作为基础入口(在Controller目录下新建一个空的Controller, 起名字就为Home 即可)

      

    然后在Home Controller的Index Action上右键点击来增加Index View: (就选空的View就可以,测试嘛,能简单就简单)

    并将Home/Index View中修改为以下代码:

    @{
        ViewBag.Title = "Hello EF6";
    }
    <h2>Hello EF6</h2>
    <div>
        <ul>
            <li>@Html.ActionLink("Home", "Index", "Home")</li>
            <li>@Html.ActionLink("About", "About", "Home")</li>
            <li>@Html.ActionLink("Students", "Index", "Student")</li>
            <li>@Html.ActionLink("Courses", "Index", "Course")</li>
            <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li>
            <li>@Html.ActionLink("Departments", "Index", "Department")</li>
        </ul>
    </div>

    Step5: 在Web.config中增加 数据库字符串;

      <connectionStrings>
        <add name="SchoolContext" connectionString="Data Source=(localdb)ProjectsV13;Initial Catalog=EFTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;" providerName="System.Data.SqlClient"/>
      </connectionStrings>  

    注:可以点击 SQLServer Object Explorer中的数据库,然后在 属性页中,可以拷贝出该数据库的连接字符串;

     

     Step6: 正式开始EF学习测试相关的操作:

      6.1 在Models目录下新建 Student类

    using System;
    using System.Collections.Generic;
    
    namespace EFTest.Models
    {
        public class Student
        {
            public int ID { get; set; }
            public string LastName { get; set; }
            public string FirstMidName { get; set; }
            public DateTime EnrollmentDate { get; set; }
    
            public virtual ICollection<Enrollment> Enrollments { get; set; }
        }
    }

      6.2 在Models目录下新建Course类

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace EFTest.Models
    {
        public class Course
        {
            [DatabaseGenerated(DatabaseGeneratedOption.None)]
            public int CourseID { get; set; }
            public string Title { get; set; }
            public int Credits { get; set; }
    
            public virtual ICollection<Enrollment> Enrollments { get; set; }
        }
    }

      6.3 在Models目录下新建Enrollment类

    namespace EFTest.Models
    {
        public enum Grade
        {
            A, B, C, D, F
        }
    
        public class Enrollment
        {
            public int EnrollmentID { get; set; }
            public int CourseID { get; set; }
            public int StudentID { get; set; }
            public Grade? Grade { get; set; }
    
            public virtual Course Course { get; set; }
            public virtual Student Student { get; set; }
        }
    }

        通过类定义可以看到: 一个学生可以选修多个课程(有多个课程记录),一个课程可以多个学生选修(有多个学生记录);
        一个课程记录对应一个学生一门课程;

        那么对于课程记录,学生ID和课程ID就是外键;必须先存在某个学生,才可以有这个学生的课程记录,也必须先存在某个课程,才可以由这个课程的课程记录;

      6.4 新建一个DAL文件夹(数据访问层),新建 SchoolContext 类和SchoolInitializer类;

        说明:SchoolContext类从DbContext继承,并在构造函数中定义 数据库字符串名:base("SchoolContext") ,然后通过DbSet<T>定义数据库模型;

                最后还重载了OnModelCreating方法,用来改变一些约束;(如果例子中的表名不用变复数,以及其它约束,比如改表名、列名等等);   

    using EFTest.Models;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration.Conventions;
    
    namespace EFTest.DAL
    {
        public class SchoolContext : DbContext
        {
            public SchoolContext() : base("SchoolContext")
            {
            }
    
            public DbSet<Student> Students { get; set; }
            public DbSet<Enrollment> Enrollments { get; set; }
            public DbSet<Course> Courses { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            }
        }
    }

        说明:SchoolInitializer类用来定义数据库在初始化的时候需要做的一些事情;比如通过重载Seed方法预先放入一些数据等;

    using System;
    using System.Collections.Generic;
    using EFTest.Models;
    
    namespace EFTest.DAL
    {
        public class SchoolInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<SchoolContext>
        {
            protected override void Seed(SchoolContext context)
            {
                var students = new List<Student>
                {
                new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
                };
    
                students.ForEach(s => context.Students.Add(s));
                context.SaveChanges();
                var courses = new List<Course>
                {
                new Course{CourseID=1050,Title="Chemistry",Credits=3,},
                new Course{CourseID=4022,Title="Microeconomics",Credits=3,},
                new Course{CourseID=4041,Title="Macroeconomics",Credits=3,},
                new Course{CourseID=1045,Title="Calculus",Credits=4,},
                new Course{CourseID=3141,Title="Trigonometry",Credits=4,},
                new Course{CourseID=2021,Title="Composition",Credits=3,},
                new Course{CourseID=2042,Title="Literature",Credits=4,}
                };
                courses.ForEach(s => context.Courses.Add(s));
                context.SaveChanges();
                var enrollments = new List<Enrollment>
                {
                new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
                new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
                new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
                new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
                new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
                new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
                new Enrollment{StudentID=3,CourseID=1050},
                new Enrollment{StudentID=4,CourseID=1050,},
                new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
                new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
                new Enrollment{StudentID=6,CourseID=1045},
                new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
                };
                enrollments.ForEach(s => context.Enrollments.Add(s));
                context.SaveChanges();
            }
        }
    }

    Step7:  定义数据库初始化(本章不涉及数据库迁移等,迁移以后再说)

       第6步定义了上下文类以及初始化类,那么怎么让应用在执行时候进行数据库初始化动作?

         有两种方式:(只能选一种)

         1、在Web.config 中定义:

                     在<entityFramework>节点中,增加<contexts>节点,分别定义<context>的type ,以及初始化<databaseInitializer>的type:  (具体为啥这样定义,只能以后看原理。。。)

    <entityFramework>
        <contexts>
          <context type="EFTest.DAL.SchoolContext, EFTest">
            <databaseInitializer type="EFTest.DAL.SchoolInitializer, EFTest" />
          </context>
        </contexts>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
          <parameters>
            <parameter value="mssqllocaldb" />
          </parameters>
        </defaultConnectionFactory>
        <providers>
          <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
      </entityFramework>

         2、在Global.asax中执行初始化;在Application_Start()方法中,最后加上以下数据库初始化代码:

        Database.SetInitializer<SchoolContext>(new SchoolInitializer());

      注:第1种方法,在Home/Index页面打开的时候是不会初始化数据库的,因为还没操作数据库读写。。。下面加访问页面来进行数据库读取;

    Step8: 增加一个 Student Controller  , 直接选择空白的就可以,通过敲入代码来更多理解:

    先为Student控制器加一个SchoolContext db , 然后把Student/Index的return View()改为如下:

    using EFTest.DAL;
    using System.Linq;
    using System.Web.Mvc;
    
    namespace EFTest.Controllers
    {
        public class StudentController : Controller
        {
            private SchoolContext db = new SchoolContext();
    
            // GET: Student
            public ActionResult Index()
            {
                return View(db.Students.ToList());
            }
        }
    }

    为Index Action加View, 选择List模板 , Model 选Student , 然后再选择好上下文类:

    注:如果出现以下错误,则表示先要编译一下,再建View

    Step9: 执行起来看看 Student/Index 页面:

    也可以查看一下数据库,已经新建成功:

    学习整理总结:

      1、根据ASP.NET MVC的概念,约定大于配置,EF6同样存在;

          数据类定义中,如果名为ID的,则自动为主键,如果为类名+ID的,也会自动为主键; 其他属性名自动为列表;如果为int型,则会默认为自增长主键;

          比较神奇的是外键的自动创建,这个约束描述起来好累,实际看看代码和实际数据库的外键就能明白;

           (通过加 virtual 描述来实现延时数据加载,即程序用到这个属性定义的数据时,才会去查数据库)

      2、 既然有约定就可以改变约定;

          可以通过对属性增加 Annotations注释 来改变约定,例如:修改主键不要为自增加主键,改变列表,增加其他列为主键,设定字段长度等等;

          如:[DatabaseGenerated(DatabaseGeneratedOption.None)]

            

  • 相关阅读:
    给Linux添加google搜索命令
    安卓设置脚本开机自启动
    重读The C programming Lanuage 笔记四:c预处理
    重读The C programming Lanuage 笔记三:简单计算器程序
    重读The C programming Lanuage 笔记二:运算符优先级
    重读The C programming Lanuage 笔记一:类型转换
    【 转】 C/C++结构体和联合体的区别
    python 柯里化 和装饰器
    qq bug 一个
    网站收集
  • 原文地址:https://www.cnblogs.com/jacky-zhang/p/7373607.html
Copyright © 2020-2023  润新知