学习笔记:EF(Entity Framework)详解

ORM(Object Relational Mapping)

要想学习EF框架,就需要知道什么ORM,ORM中文名叫对象关系映射。
我们来看一下定义:用于实现面向对象编程语言里不同类型系统的数据之间的转换。
emmm,感觉还不是很明确,简单的来说,ORM提供了实现数据层的另一种模式,它采用映射元数据来描述对象关系的映射,使得ORM中间件能在任何一个应用的业务逻辑层和数据库层之间充当桥梁。
ORM的方法论基于三个核心原则:

  • 简单:以最基本的形式建模数据。
  • 传达性:数据库结构被任何人都能理解的语言文档化。
  • 精确性:基于数据模型创建正确标准化了的结构。

让我们从O/R开始。O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。
当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,而这些代码写起来总是重复的。

ORM解决的主要问题是对象关系的映射。域模型和关系模型分别是建立在概念模型的基础上的。域模型是面向对象的,而关系模型是面向关系的。一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录,类的每个属性对应表的每个字段。

总结一下ORM的特点:
提高了开发效率。由于ORM可以自动对Entity对象与数据库中的Table进行字段与属性的映射,所以我们实际可能已经不需要一个专用的、庞大的数据访问层。

什么是EF?

实体框架EF(Entity Framework) 是 ADO.NET 中的一组支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架。
就是说,EF是基于ADO.NET的,一种使用ORM技术的框架。
在这里插入图片描述
从上图可以看出,EF框架在底层是通过调用ADO.NET来实现数据库操作的。
多转一道弯性能和灵活性肯定会受到影响,所以本文最后也会有ADO.NET教程链接,各位看过以后再比较EF和ADO.NET的优劣之处。

EF 的第一个功能就是建立一个实体数据模型(EDM),主要包括概念模型,存储模型以及概念和存储之间的映射。EF使用此EDM执行CRUD操作。它使用EDM从LINQ查询构建SQL查询,构建INSERT,UPDATE和DELETE命令,将数据库结果转换为实体对象。
在这里插入图片描述
查询
EF 使用EDM将LINQ-to-Entities查询转换为关系数据库的SQL查询,并将结果转换回实体对象。
在这里插入图片描述
保存
当调用SaveChanges()方法时,EF根据实体的状态推断INSERT,UPDATE和DELETE命令。ChangeTrack跟踪每个实体的状态,以及何时执行任何操作。
在这里插入图片描述

EF代码实操

在数据库中新建两张表
在这里插入图片描述
我在Winform程序中创建ADO.NET实体数据模型
在这里插入图片描述
然后一直点击下一步,记得看一下数据库中要用的表有没有被选上,一般默认是全选上的。
自动生成好以后是长这样的,我们着重看一下画红框的这两个类
在这里插入图片描述
先来看一下实体类,这就是普通的实体类嘛,没有什么区别,顺便讲一下 “?” 表示可空类型

    public partial class Student
    {
        public int F_id { get; set; }
        public string F_name { get; set; }
        public int? F_age { get; set; }
        public string F_hobby { get; set; }
    }
    public partial class Subject
    {
        public int F_id { get; set; }
        public int F_stuId { get; set; }
        public string F_subject { get; set; }
        public decimal? F_score { get; set; }
    }

DbContext

DbContext是EntityFramework很重要的部分,连接域模型与数据库的桥梁,是与数据库通信的主要类。

主要负责以下活动:

  • EntitySet::DbContext包含了所有映射到表的entities
  • Querying:将Linq-To-Entities转译为Sql并发送到数据库
  • Change Tracking:从数据库获取entities后保留并跟踪实体数据变化
  • Persisting Data:根据entity状态执行Insert、update、delete命令
  • Caching:DbContext的默认第一级缓存,在上下文中的生命周期中存储entity
  • Manage Relationship:DbContext在DbFirst模式中使用CSDL、MSL、SSDL管理对象关系,Code first中使用fluent api 管理关系
  • Object Materialization:DbContext将物理表转成entity实例对象

那么我们具体来看一下Context这个类,这个类的作用主要是连接数据库和映射数据表,所以每次想要增加一张新表的时候我们需要在这个类中加一个DbSet的语句来通知EF映射表关系。

扫描二维码关注公众号,回复: 5856529 查看本文章
    //他是一个抽象类,继承了DbContext
    public partial class TestDemoEntities : DbContext
    {
    	//构造方法,base的意思是使用config文件中名为TestDemoEntities的连接字符串连接数据库
        public TestDemoEntities() : base("name=TestDemoEntities")
        {
        }
    	
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
        
    	//映射实体类和数据库中的物理表
        public virtual DbSet<Student> Student { get; set; }
        public virtual DbSet<Subject> Subject { get; set; }
    }

CRUD

那么现在又到了老生常谈的CRUD问题了,既然EF是映射实体类和物理表,那怎么使用呢?来看代码

    public partial class Form1 : Form
    {
    	//实例化Context对象
        TestDemoEntities db = new TestDemoEntities();

        public Form1()
        {
            InitializeComponent();
        }

        //查找全部
        private void btn_query_Click(object sender, EventArgs e)
        {
        	//查询所有数据放到list中
            List<Student> list = db.Student.ToList();
            textBox1.Text = "序号\t姓名\t年龄\t爱好\r\n";
            foreach(Student stu in list)
            {
                textBox1.Text += stu.F_id + "\t" + stu.F_name + "\t" + stu.F_age + "\t" + stu.F_hobby + "\r\n";
            }
        }

        //增加数据
        private void btn_insert_Click(object sender, EventArgs e)
        {
        	//通过Add方法将实例化的Student对象中的属性放到Student实体对象中
            db.Student.Add(new Student() {F_name="阿强", F_age=33, F_hobby="游泳" });
            //执行增删改方法必须执行SaveChanges()方法,目的将执行结果保存到数据库,返回影响的行数
            int result = db.SaveChanges();
            if (result > 0)
                MessageBox.Show("添加成功!");
            else
                MessageBox.Show("添加失败!");
        }

        //修改数据
        private void btn_edit_Click(object sender, EventArgs e)
        {
        	//先根据id取出数据库中这条记录放到实体对象中
            var student = db.Student.FirstOrDefault(s => s.F_id == 2);
            //修改实体对象的属性值
            student.F_hobby = "跳绳";
            //保存
            int result = db.SaveChanges();
            if (result > 0)
                MessageBox.Show("修改成功!");
            else
                MessageBox.Show("修改失败!");
        }

        //删除数据
        private void btn_delete_Click(object sender, EventArgs e)
        {
        	//定义一个实体对象,将id设置为要删除的id值
            Student stu = new Student() { F_id = 2};
            //将对象附加到上下文中
            db.Student.Attach(stu);
            //删除该对象
            db.Student.Remove(stu);
            //保存
            int result = db.SaveChanges();
            if (result > 0)
                MessageBox.Show("删除成功!");
            else
                MessageBox.Show("删除失败!");
        }
    }

当然,上述实现了基本的增删改查操作,但是绝对不可能解决所有的情况,具体解决方式要根据具体情况进行分析,下面我再写几个常见的情况。

只查找一条记录

Student stu = db.Student.Where(s => s.F_id == 1).FirstOrDefault();

根据条件查找列表

List<Student> list = db.Student.Where(s => s.F_age > 18).ToList();

批量删除

List<Student> list = db.Student.Where(s => s.F_age > 18).ToList();
if(list != null && list.Any())
{
    foreach(Student stu in list)
    {
        db.Student.Remove(stu);
    }
}

总结

综上所述,发现EF其实也就是操作数据库的一个中间组件,与ADO.NET的功能一样,而且是基于ADO.NET的,性能上肯定会比ADO.NET差(大数据量才会体现),那么为什么还要用EF呢?
个人认为,就是两个字,简便。用EF的话大家会发现与ADO.NET相比代码简洁了不少,没有了SqlHelper,也不用写sql语句了,结合Lambda表达式很轻松地就可以操作数据库,但是EF的灵活性和性能的确没有ADO.NET好,所以实际开发我们一般结合EF和ADO.NET混合开发。
一项技术的出现必然使得代码走向简洁,别觉得会一种技术就高枕无忧不去学习其他类似技术了,技术本身不会有好坏之分,只是使用场景不同技术的优劣就会体现,说白了,没有最好的,只有最合适的。
在这里插入图片描述
想了解ADO.NET的童鞋可以看我另一个教程 ADO.NET详解

猜你喜欢

转载自blog.csdn.net/weixin_42103026/article/details/88976923