• Entity Framework 实体数据模型——数据处理


     一、关于 DbContext

      在 Entity Framework 环境下,程序通过实体数据模型与底层数据库进行沟通。

      数据模型是一个继承自 DbContext 的自定义类文件,也就是context。

      无论是使用 “EF 设计器” 还是 “Code First”,都必须经由 context 进行数据库的互动操作。

      下面通过实例来介绍下 DbContext 对象。

      通过已有的数据库,选择 “来自数据库的Code First” 模式来建立实体数据库模型实例。

       

         通过模型类 StudentInfoDBModel 可以看出,它继承自 DbContext 并在 EF 中负责几项关键任务。

         对 DbSet<T> 类对象的管理,每一个DbSet<TEntity> 对象都是封装特定数据的实体集(Entity Set)对象,

      实体集映射到底层数据库的特定数据表。

      在 EF 环境中对任何数据库执行的存取操作,都会生成对应到连接数据库的SQL语句,

      而 EF 负责将语句放到数据库中执行并返回执行结果。

       

      在 Program.cs 类的 Main 方法中添加如下代码:

      using (var context = new StudentInfoDBModel())  // DbContext 对象会占用资源,通常我们会使用 using 语句来创建对象实例
      {
          IEnumerable<Student> stus = from stu in context.Student select stu;
          string sql = stus.ToString();
          Console.WriteLine($"{sql}");
      }
      Console.ReadLine();

      运行程序:

      

      可以看到EF生成了对应的SQL语句。

      当我们想要读取到对应的数据时,这段SQL将被传递给数据库去进行执行,并返回相应的执行结果。

      然后通过 Context 对象将返回的数据转换成对应的可枚举的 IEnumerable<Student> 集合对象。

     static void Main(string[] args)
     {
         using (var context = new StudentInfoDBModel())  
         {
             IEnumerable<Student> stus = from stu in context.Student select stu;
             string sql = stus.ToString();
             Console.WriteLine($"{sql}");
             foreach (var stu in stus)
             {
                 Console.WriteLine(stu.Name);
             }
         }
         Console.ReadLine();
     }

      EF 除了负责产生SQL语句外,还会管理SQL的传送与返回的数据封装,因此我们只需处理LINQ

      与数据对象即可。因此避免了因编写SQL而导致的错误和安全问题。

      1、 连接与查询

        EF 的数据库连接由 DbContext 自行维护,当一个查询开始执行时,连接便会适时的打开,直到查询结束再自动关闭连接。

        连接是相对耗费资源的操作,因此我们需要了解下 EF 是在何时进行SQL语句传递的,以避免不必要的性能耗费。那么,

        DbContext 会在何时去执行查询操作呢?

        ① 进行遍历对象时

          比如上面的 LINQ 语句,当程序执行到这段LINQ时,查询操作其实并不会马上执行,而是在执行 foreach 语句时,

          查询操作才会执行。

        ② 类型转换时

            LINQ 语句返回的通常是 IEnumerable 或 IQueryable 对象,有时我们会将其转换成 List 类的对象,在进行类型装换

            的过程中(比如调用 ToList()、ToArray()、ToDictionary()等方法时),也会执行查询操作。

          

        ③ 调用任何针对LINQ结果执行的方法时,如调用 Count()、First()等方法时。

          

        ④ 重新加载实体数据时

          比如在进行更新操作以后,想要获取最新的数据内容时,可以通过重载来达到目的,这个时候查询就会再被执行一次。

      2、  管理更新操作

           EF 中的变动更新操作

         using (var context = new StudentInfoDBModel())
         {
             Student stu = context.Student.First();   // 获取 Student 表中的第一条记录
             Console.WriteLine($"姓名:{stu.Name} 	 年龄:{stu.Age}");
     
             stu.Age = 18;   // 更新年龄
             context.SaveChanges();  // SaveChanges()方法保存变更到数据控中
             Console.WriteLine($"姓名:{stu.Name} 	 年龄:{stu.Age}");
     
             //重载
             context.Entry(stu).Reload();
             stu = context.Student.First();
             Console.WriteLine($"姓名:{stu.Name} 	 年龄:{stu.Age}");
         }
         Console.ReadLine();

        可以看到,在更新年龄之后,程序调用了 context.SaveChanges(); 方法将更新后的数据保存到了数据库中。

        这么一来数据对象就发生了改变,如果想要实时获取更新后的数据内容,那么就需要进行重载 DbContext 对象。

        以上示例中调用的 First()方法 和 Reload() 重载方法都会导致连接的建立,并且执行底层数据库的查询操作。

      3、  DbContext 对象的生命周期

        DbContext 对象会占用资源,通常我们会使用 using 语句来创建对象实例,当 using 区块结束时,对象的生命

        周期也就相应的结束了,并且会释放其占用的资源。

        如果直接创建 DbContext 对象,就必须调用 Dispose 方法;如果不调用该方法的话,就只能等待系统的资源

        回收机制去进行资源释放了。

      4、 管理与操作数据库(Database属性)

        DbContext 有一个 Database 属性,它会返回一个 System.Data.Entity.Database 对象,为 DbContext 提供连接数据库的支持。

        

         这行代码获取了 Database 对象,我们可以通过 db 变量来执行有关数据库的操作。

        Database 中有一组 log 属性支持获取 DbContext 生成的 SQL 记录。我们可以通过该属性来追踪程序运行过程中所使用的SQL。

         using (var context = new StudentInfoDBModel()) 
         {
             context.Database.Log = Console.WriteLine;  // 通过该配置,可以跟踪程序执行中所用到的 SQL 语句
             IEnumerable<Student> stus = from stu in context.Student select stu;
             foreach (var item in stus)
             {
                 Console.WriteLine(item.Name);
             }
         }
         Console.ReadLine();

        

         我们还可以通过 context.Database.Connection 对象来获取连接的相关信息。

          using (var context = new StudentInfoDBModel()) 
          {
              DbConnection dbCon = context.Database.Connection;   // 获取数据库的连接对象
              string conn = dbCon.ConnectionString;               // 获取数据库的连接字符串
              string dbName = dbCon.Database;                     // 获取数据库名称
              string serverName = dbCon.DataSource;               // 获取要连接到数据库服务器的名称。
              System.Data.ConnectionState state = dbCon.State;    // 获取连接状态
    
              Console.WriteLine($"连接字符串:{conn} 
    数据库:{dbName} 
    服务器:{serverName} 
    状态:{state}");
          }
          Console.ReadLine();

      5、ObjectContext

         在 EF 4.1 之前,支持数据库操作功能实现的类必须继承 ObjectContext,直到 EF 4.1 之后更易于使用的 DbConext

        才被公布了出来,成为了默认的继承类,ObjectContext 可视为轻量级版的 DbContext,而 DbContext 依然实现了 

        IObjectContextAdapter.ObjectContext 属性,以返回底层的 ObjectContext 对象。

         System.Data.Entity.Core.Objects.ObjectContext objDbCont = (context as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext;

        DbContext 简化了 ObjectContext 的用法:

         using (var context = new StudentInfoDBModel()) 
         {
             // ObjectContext
             ObjectContext objDbCont = (context as IObjectContextAdapter).ObjectContext;
             ObjectSet<Student> objStu = objDbCont.CreateObjectSet<Student>();
             var oq = (ObjectQuery)objStu.Where(s => s.Age > 16);
             Console.WriteLine(oq.ToTraceString());
             foreach (Student item in oq)
             {
                 Console.WriteLine(item.Name);
             }
    
             // DbContext
             var stu = context.Student.Where(s => s.Age > 16);
             Console.WriteLine(stu.ToString());
             foreach (var st in stu)
             {
                 Console.WriteLine(st.Name);
             }
         }
         Console.ReadLine();

        

         不同的实现方式,预期的效果相同,相比之下 DbContext 更为简洁。

    二、关于 DbSet

      1、DbSet

        DbSet 也是 EF 重要的类之一,表示实体模型中的特定实体对象集合。

        当 DbContext 将查询送入数据库并获取返回的数据时,这些数据将被转换为对应的实体类对象,然后存储在 

        DbSet 中,并通过 DbContext 对象属性公开,以供程序提取。

        DbSet 实现了 IEnumerable 接口,所以支持 LINQ 语法和方法。程序通过 LINQ 生成原始的 SQL 语句,并

        由 DbContext 传送至数据库执行。我们可以通过 ToString() 方法来获取对应的 SQL 语句。

         using (var context = new StudentInfoDBModel())
         {
             string sql = context.Student.ToString();
             Console.WriteLine(sql);
         }
         Console.ReadLine();

        上面的 context.Student 会返回 DbSet<Student> 对象,其中封装了来自 Student 表的内容,因此我们可以通过

        ToString() 的方法来获取到对应的 SQL 语句。

        

      2、查询数据(Find() 方法)

        Find() 方法必须指定所有主键值才能正确地执行。

         using (var context = new StudentInfoDBModel())
         {
             Student stu = context.Student.Find(5);
             if (stu != null)
                 Console.WriteLine(stu.Name);
             else
                 Console.WriteLine("不存在");
         }
         Console.ReadLine();

        Find(5) 表示查找 ID 字段值为 5 的一条数据。

        Find() 方法必须传入实体类中定义的所有主键属性才能正确的进行查找。

        也就是说 Find() 方法是基于主键进行查找的。如果复合式索引主键,就需要依次传入所有主键字段。否则:

        

        注意: Find() 方法查找数据的方式在性能方面要优于 LINQ 的方式。

      3、执行原始的 SQL 语句

         如果想要直接执行已有的 SQL 语句,可以通过调用 SqlQuery() 方法:

          using (var context = new StudentInfoDBModel())
          {
              SqlParameter sqlPara = new SqlParameter("Age", 16);
              var stus = context.Student.SqlQuery("select * from Student where Age > @Age", sqlPara);
              foreach (var stu in stus) 
              {
                  Console.WriteLine(stu.Name);
              }
          }
          Console.ReadLine();

      4、数据变动与更新

           DbSet 支持对象的变动和更新。无论是修改或删除集合中的数据,还是往集合中添加数据,这些针对 DbSet 执行的操作,

        都会随着调用 SaveChange 方法同步更新到 DBContext 所连接的数据库中。

        添加对象需调用 Add() 方法:

         using (var context = new StudentInfoDBCModel())
         {
             Student sun = new Student
             {
                 Name = "孙悟空",
                 Age = 12,
                 Sex = false,
                 Hobby = "七十二变",
                 Birthday = DateTime.Now
             };
    
             DbSet<Student> stus = context.Student;
             stus.Add(sun);
             int result = context.SaveChanges();
             Console.WriteLine(result);
     
             foreach (var stu in stus)
             {
                 Console.WriteLine(stu.Name);
             }
         }
         Console.ReadLine();

        添加的数据量过多的话,可以通过调用 AddRange() 方法来实现:

         using (var context = new StudentInfoDBCModel())
         {
             List<Student> list = new List<Student>(){
                 new Student
                 {
                     Name = "孙悟空",
                     Age = 12,
                     Sex = false,
                     Hobby = "七十二变",
                     Birthday = DateTime.Now
                 },
                 new Student
                 {
                     Name = "猪八戒",
                     Age = 12,
                     Sex = false,
                     Hobby = "三十六变",
                     Birthday = DateTime.Now
                 }
             };
             DbSet<Student> stus = context.Student;
             stus.AddRange(list);
             int result = context.SaveChanges();
             Console.WriteLine(result);
    
             foreach (var stu in stus)
             {
                 Console.WriteLine(stu.Name);
             }
         }
         Console.ReadLine();

        修改和添加都有了,还少个删除。删除调用的是 Remove() 或 RemoveRange() 方法:

        删除的操作是针对特定的数据对象,因此在删除之前必须先获取对象。

         using (var context = new StudentInfoDBCModel())
         {
             // Remove
             Student stud = context.Student.Find(1);
             if(stud != null)
             {
                 context.Student.Remove(stud);
                 context.SaveChanges();
             }
             else
             {
                 Console.WriteLine("不存在!");
             }
     
             // RemoveRange
             IQueryable<Student> stus = context.Student.Where(s => s.Age > 6);
             context.Student.RemoveRange(stus);
             context.SaveChanges();
         }
         Console.ReadLine();
  • 相关阅读:
    Oracle第三方ado.net数据提供程序
    HTML5实战 文摘 第二章 HTML5用于创建表单的输入小部件 数据绑定以及数据验证
    reactjs & antd & redux 使用心得
    HTML5实战 文摘 第一章 从文档到应用的转变
    css的高级选择器
    <!DOCTYPE html> 是什么,它的作用是什么
    Nginx调优
    java enum 枚举简单用法
    简谈java解析HTML(org.jsoup.nodes.Document)
    jquery EasyUI tree 加载远程数据 java实现
  • 原文地址:https://www.cnblogs.com/LittleBai/p/14072975.html
Copyright © 2020-2023  润新知