zoukankan      html  css  js  c++  java
  • EF-关于类库中EntityFramework之CodeFirst(代码优先)的操作浅析

    前有ADO.NET,后有ORM模式的EntityFramework。这两种技术都实现了对数据库的访问操作。如果要说哪种技术好,就看项目架构的大小,使用者的熟练程度等等,毕竟萝卜白菜,各有所爱。

    今天要记录和讨论的是项目之数据访问层中,使用EF来操作数据库,并可以自动更新数据库表的结构。闲话休提,逻辑步骤为先!

    一、创建测试项目

    目的:创建一个简单的带有模型层和数据访问层的控制台应用程序架构。如下图:

    Model:用作模型层,对应数据库中的表;

    DAL:数据访问层,实现对数据库的操作控制。引用Model;

    EFDemo:一个简单的控制台应用程序。引用Model和DAL。

    二、创建模型

    在Model层中创建需要的模型类,模型类对应数据库中的表结构。

    1、Student模型 

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Model {
        //指定表名
        [Table("Student")]
        public class Student {
            //指定该表的主键
            [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public Guid ID { get; set; }
            public string Name { get; set; }
            public DateTime? BirthDay { get; set; }
            public int? Age { get; set; }
        }
    }

    可以像平常创建普通类型一样创建Student类。但是,将Student类创建完毕之后,要给这个类和类中的属性添加相应的特性约束,以便映射到数据库的表中。在添加相关特性之前,Model层需要引用System.ComponentModel.DataAnnotations这个类库,方便使用Table和Key等相关特性类型。如果需要将对应表中的字段映射为可空,那么在Student的属性类型后面加个问号(?)即可,如public Datetime? BirthDay;

    三、创建数据上下文

    有了数据上下文,才能在其他诸如业务逻辑层中操作数据库,当然,本次的EFDemo兼容了业务逻辑层。

    接下来,我们在数据访问层(DAL)中创建数据上下文。

    创建步骤:

    1、查看DAL中是否包含了EntityFramework的引用,如果没有,就使用NuGet管理工具包去安装EntityFramework。

    可以看见当前的DAL中,没有包含对EntityFrameword的引用。接下来,我们使用 管理NuGet程序包去添加。在这里,稍微废话一点,NuGet其实可以看做New-Get,没错,就是获取新东西的意思。NuGet是一个好东西,它就像一个图书馆,里面存放着各式各样的dll包,我们可以使用它去获取当前没有的dll文件包。

    右键点击“引用”,就会看到菜单里面有一个“管理NuGet程序包(N)...”的子项,点击该菜单子项。

    进入 NuGet程序包管理器 界面之后,就会看见很多程序包,而我们现在只需要EntityFramework程序包。找到EntityFramework程序包之后,点击右边界面上的“安装”按钮。

    成功安装EntityFramework程序包之后的界面。如下图:

    OK,创建数据上下文的先决条件已经具备。

    2、创建数据上下文

    在创建数据上下文之前,容我们想一下,程序是怎么知道连接哪个地址的数据库呢?通过数据库连接字符串!接下来,我们先在配置文件中创建数据库的连接字符串。需要在哪个配置文件中创建呢?不要搞错了哈,需要在应用程序的配置文件中创建连接字符串,不要在类库的配置文件中去创建哟。如下所示:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <!--Begin 创建连接字符串-->
      <connectionStrings>
        <add name="EFDemo" connectionString="server=.;Database=EFDemo;Trusted_Connection=true;" providerName="System.Data.SqlClient" />
      </connectionStrings>
      <!--End 创建连接字符串-->
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
    </configuration>

    接下来真正开始创建数据上下文类,如以下代码:

    using Model;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace DAL {
        public class DemoContext:DbContext {
            //使用name=EFDemo的连接字符串
            public DemoContext() : base("EFDemo") { }
    
            //Students属性对应数据库中的Student表
            public virtual DbSet<Student> Students { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder) {
                base.OnModelCreating(modelBuilder);
            }
        }
    }

    这么简单?就这么简单!

    能使用该数据上下文类操作数据库了吗?能!

    可是数据库中没有EFDemo数据库呢,也没有Student表呢,需要先创建吗?没那个必要,本次Demo使用的是CodeFirst(代码优先),系统会识别连接字符串中的数据库名称(Database=EFDemo)和数据上下文类型中的DbSet<Student>,通过ORM框架自动在数据库中创建并映射数据库EFDemo和表Student。这就是代码优先模式的优势,不必先创建数据库,也不必使用数据库实体创建edmx文件去映射。直接写模型类,直接创建数据上下文。剩下的事情交给EntityFramework去处理。

    不过有一点需要谨记:需要使用数据上下文在应用中操作模型类,数据库才能被创建。不过,在操作模型类之前,也可以使用数据上下文的Database属性去初始化并创建数据库,如:context.Database.Initialize(true);

    三、使用

    1、先引用EntityFramework

    在控制台应用程序中,由于需要实现对DbContext的使用,因此得先引用EntityFramework。这次引用EntityFramework不必用NuGet管理包加载。刚DAL层不是已经加载过了吗,直接到DAL项目中去引用过来就行。如下图所示:

     2、在Main方法中使用

    代码如下:

    using DAL;
    using Model;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EFDemo {
        class Program {
            static void Main(string[] args) {
    
                using (DemoContext context = new DemoContext()) {
                    //在使用模型类之前需要强制创建数据库 true:强制创建
                    context.Database.Initialize(true);
                    Student stu = new Student {
                        Name = "赵子成",
                        BirthDay = DateTime.Parse("1990-08-01"),
                        Age = 27
                    };
    
                    //新增一个Student实体,相当于在Student表中,新增一条数据
                    context.Students.Add(stu);
                    //保存
                    context.SaveChanges();
                }
            }
        }
    }

    接着,我们去数据库中看看,是否已经成功创建了EFDemo数据库和Student表呢?

     根据上图,我们可以看出,数据库EFDemo和Student表已经成功创建,并且Student表中已经成功被插入了一条记录。

    接下来,我们实现对Student表的增删查改(CRUD)操作。

    查询:

     foreach (var stu in context.Students)
                        Console.WriteLine("{0} {1} {2} {3}",stu.ID,stu.Name,stu.BirthDay,stu.Age);

    查询结果:

     修改:

                    Student stu = context.Students.Where(s => s.Age == 27).SingleOrDefault();
                    if (stu != null) {
                        stu.Name = "吴天野";
                        //设置该实体对象的状态为 修改
                        context.Entry(stu).State = System.Data.Entity.EntityState.Modified;
                        //保存
                        context.SaveChanges();
                    }

    修改结果:

    删除:

                    //针对删除操作,只需要知道一个实体的主键就可以将之从数据库中删除
                    //如果不知道主键,也可以用其他方式从数据库中查出该实体的数据,从而将之删除
                    Guid id = new Guid("B1048903-0074-E711-970D-58FB84575557");
                    Student stu = context.Students.Find(id);
                    if (stu != null) {                  
                        //设置该实体对象的状态为 删除
                        context.Entry(stu).State = System.Data.Entity.EntityState.Deleted;
                        //保存
                        context.SaveChanges();
                    }

    删除结果:

    四、自动更新数据库结构

    在开始之前,让我们来做一个小实验。在Model层的Student类中新增一个属性Address。如下代码:

        [Table("Student")]
        public class Student {
            //指定该表的主键
            [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public Guid ID { get; set; }
            public string Name { get; set; }
            public DateTime? BirthDay { get; set; }
            public int? Age { get; set; }
    
            public string Address { get; set; }
        }

    新增完成后,运行代码试试,看能成功运行否?肯定不能!会出现如下图的异常:

    这是个什么错呢?因为数据库已经被创建,但是我们在代码中修改了模型类Student的结构。这是由于该Student类的结构和数据库中Student表的结构不一致造成的。怎么解决呢?使用迁移技术。

    请继续下一篇文章:EF-使用迁移技术让程序自动更新数据库表结构

  • 相关阅读:
    java 反射 invoke()的异常问题记录
    windows安装nginx可视化工具nginxWebUI
    Springboot+Mybatis+Clickhouse+jsp 搭建单体应用项目(三)(添加增删改查)
    Springboot+Mybatis+Clickhouse+jsp 搭建单体应用项目(二)(添加日志打印和源码地址)
    Springboot+Mybatis+Clickhouse+jsp 搭建单体应用项目(一)
    mac + docker+单击clickhouse+Dbeaver安装全套
    线程中使用for循环的add或remove方法的两种方案
    map数据按照list排序
    oracle dbca 【bug】:JAVA_JIT_ENABLED=false
    Ubuntu(Debian):apt-get:处理repository数字签名无效、过期、没有签名:即 如何强制 apt-get update?
  • 原文地址:https://www.cnblogs.com/williamwsj/p/7253910.html
Copyright © 2011-2022 走看看