EntityFramework(1)基础概念与Database First
基本概念
EntityFramework是微软推出的一款ORM工具,关于ORM的概念请参考博客https://www.cnblogs.com/huanhang/p/6054908.html。这篇文章对ORM进行很详细的介绍。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
在.NET3.5之前我们从数据库检索或者存储数据的方式经常都是ADO.NET。操作数据会经历如下步骤,打开数据库连接,创建一个数据集来获取或提交数据到数据库,将数据集中的数据转换为.NET对象。或者反过来应用业务规则。这是一个繁琐且重复的工作,或许会有一些Helper来帮助我们解决数据库连接方面的工作,但是数据集到领域对象的过程是我们需要一次次去映射的。所以,ORM工具就提供给了我们操作业务对象,由ORM对我们操作的对象进行数据库操作映射。EntityFramework就是这样的一种工具,我们使用Linq操作领域对象,EntityFramework会帮我们将对应操作转换为SQL语句,然后连接到数据库执行。这样我们就可以在更高的抽象层面来处理数据,并且与传统应用程序相比,可以用更少的代码创建和维护面向数据的应用程序。关于EntityFramework的概念和介绍可以参考MSDN或者http://www.entityframeworktutorial.net/what-is-entityframework.aspx。以上部分概念也来源于此网站。另外,EntityFramework Core为EF垮平台版本。好了,下面进入EntityFramework的具体使用部分。
EntityFramework的3中使用模式
EntityFramework有3中使用模式
- DataBase First:从数据库开始,在数据库已经存在的情况下。通过数据库结构构建实体映射对象,并生成映射元数据
- Model First:使用EntityFramework提供给的模型创建工具创建数据模型与映射元数据,通过这些元数据信息创建数据库
- Code First:通过DDD创建领域对象并配置映射规则,数据迁移规则。EF会根据领域对象模型与映射规则来创建数据库
下面我们依次来看看3种模式在实际的编码过程中怎么使用,示例程序使用SQL Server2016数据库引擎,Northwind数据库。开发工具为VS2017。
1 Database First数据模型定义
1,创建控制台应用Demo.DatabaseFirst
2,安装EntityFramework Nuget包,示例程序版本为6.2.0
3,添加实体数据模型,在Data模板下选择ADO.NET实体数据模型,命名为DemoModel
4,因为我们是从数据库生成实体数据模型,所以,我们选择来自数据库的EF设计器
5,进行数据库配置,由于我这里之前配置过数据库,所以会有之前的连接信息,此处,我们新建数据库连接,点击新建连接
6,配置数据连接,并选择数据库。在高级选项中,有关于连接配置的选项,可以根据需要修改。
7,配置完成后,点击下一步选择需要生成实体数据模型的表(视图,存储过程或者函数)
8,点击完成,此时,从数据库映射的实体数据模型已经生成。我们可以看一下,在解决方案结构中,EF帮我们新建了哪些文件,在配置文件中又帮我们加入了哪些内容
DemoModel.edmx就是EF帮我们生成的数据模型,双击之后,我们可以看到我们选中的表已经映射成为了实体数据模型。生成模型的规则是EF定义的模板文件(XXX.tt),不同的EF版本有不同的模板文件,我们也可以自定义模板文件。我们右键点击某个模型,可以看到如下图的菜单。从数据库更新模型,当数据库发生更改的时候,我们可以通过点击此菜单来将数据库的更改映射到模型。表映射可以查看实体数据类型与表的映射,属性与列信息的映射信息等等。我们也可以查看数据模型的属性,在空白处点击右键,选择属性。可以看到数据模型的选项,有数据库的连接字符串信息,是否延迟加载等等,可以根据需求自行更改配置。
实体关系:从edmx设计中可以看到,实体之间的连接线有1…*,*…*,0..1的关联属性,这些关系实际上映射的就是数据库中表之间的关系,也就是我们常说的,一对一,多对多,一对多。实体数据模型会根据数据库中的主外键信息自动生成关系模型数据。选中连接线,右键查看属性,可以查看实体之间关系的具体信息。
导航属性:上面说了,实体与实体之间是存在关系的,那么怎么从一个实体去访问另外一个与他有关系的实体呢,实际上我们通过导航属性。导航属性实际上就是实现了从一个实体到另一个关联实体的访问机制。
实体数据模型实际上包含了实体对象信息,数据库元数据信息,对象与数据库的映射信息。那么这些信息是在哪里定义的呢,我们使用文本编辑工具打开DemoModel.edmx文件,可以看到edmx实际上是一个xml文件,这个xml文件的主要节点如下
1,edmx:StorageModels(逻辑层SSDL):SSDL主要定义了数据库中表,列,关系,视图,函数等
2,emdx:ConceptualModels(概念层CSDL):CSDL主要定义了数据模型的实体类型,这些实体暴露给上层来操作实体数据
3,edmx:Mappings(映射层):SSDL与CSDL之间的关系映射
2 Database First数据模型操作
EntityFramework使用了上述的xml文件定义了,实体,数据库对象,与他们之间的关系。至此,我们完成了EntityFramework的实体数据映射并分析了基本原理。定义数据模型的意义在于操作数据,下面我们使用数据模型来进行数据的增删改查。我们新建类CategoryServices,并添加AddCategory,UpdateCategory,DeleteCatetory,GetCatetories四个方法
2.1增加数据
public bool AddCategory(Category category) { using (NorthwindEntities context = new NorthwindEntities()) { context.Categories.Add(category); return context.SaveChanges()>0; } }
2.2修改数据
public bool UpdateCategory(Category category) { bool reuslt = false; using (NorthwindEntities context = new NorthwindEntities()) { Category currentCategory = context.Categories .FirstOrDefault(parm => parm.CategoryID == category.CategoryID); if (currentCategory != null) { currentCategory.Description = category.Description; reuslt = context.SaveChanges() > 0; } return reuslt; } }
2.3删除数据
public bool DeleteCatetory(int id) { bool reuslt = false; using (NorthwindEntities context = new NorthwindEntities()) { Category currentCategory = context.Categories .FirstOrDefault(parm => parm.CategoryID == id); if (currentCategory != null) { context.Categories.Remove(currentCategory); reuslt = context.SaveChanges() > 0; } return reuslt; } }
2.4查询数据
public List<Category> GetCatetories() { using (NorthwindEntities context = new NorthwindEntities()) { return context.Categories.ToList(); } }
调用代码
class Program { static void Main(string[] args) { CategoryServices services = new CategoryServices(); List<Category> categories = services.GetCatetories(); categories.ForEach(parm => Console.WriteLine($"{parm.CategoryName}---{parm.Description}")); Console.WriteLine("---select---"); Category category = new Category { CategoryName = "Microsoft", Description = "this is Microsoft" }; bool result = services.AddCategory(category); Category categoryAdd = services.GetCatetories().LastOrDefault(); Console.WriteLine($"{categoryAdd.CategoryName}---{categoryAdd.Description}"); Console.WriteLine("---add---"); Category categoryUpdate = new Category { CategoryID = categoryAdd.CategoryID, CategoryName = "Microsoft", Description = "this is Microsoft update" }; bool updateResult = services.UpdateCategory(categoryUpdate); Console.WriteLine($"{categoryUpdate.CategoryName}---{categoryUpdate.Description}"); Console.WriteLine("---update---"); int catetoryId = categoryAdd.CategoryID; bool deleteUpdate = services.DeleteCatetory(catetoryId); Category categoryLast = services.GetCatetories().LastOrDefault(); Console.WriteLine($"{categoryLast.CategoryName}---{categoryLast.Description}"); Console.WriteLine("---delete---"); Console.ReadLine(); } }
执行结果
如下图执行结果,第一步我们打印了所有的Category,第二步我们添加一条Category,紧接着我们修改了添加的这条数据,最后我们删除这条数据。可以看到,增删改查操作完成。是不是感觉操作数据库也可以像操作对象一样简单,便捷。
数据操作基本概念
DbContext:上面的实例中,我们实例化了类型NorthwindEntities。这个在我们配置数据库连接的时候输入的上下文名称。实际上,在EntityFramework帮助我们生成数据模型时,也同时帮我们生成了继承与DbContext类型的数据上下文,我们这里是NorthwindEntities。那么数据上下文是什么呢。数据上下文实际是真实与数据库交互的桥梁。前面的章节我们定义了对象,数据,映射,这些都是基础设施,也是基础结构。在操作数据时,比如添加数据。最终数据库能执行的操作只会是SQL语句,存储过程等。所以 ,数据上下文监测了我们对实体类型的更改,在调用SaveChange时将我们对上下文中实体的更改转换成SQL语句发送给数据库执行,我们可以打开SQL Server监视工具来查看EntityFrameworkSaveChange后生成的SQL语句。所以,在了解了ORM的核心概念后,其实,如果我们愿意,也可以自己实现一套ORM工具。
下面的代码就是EntityFramework生成的继承自DbContext的数据上下文。
namespace Demo.DatabaseFirst { using System; using System.Data.Entity; using System.Data.Entity.Infrastructure; public partial class NorthwindEntities : DbContext { public NorthwindEntities() : base("name=NorthwindEntities") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { throw new UnintentionalCodeFirstException(); } public virtual DbSet<Category> Categories { get; set; } public virtual DbSet<CustomerDemographic> CustomerDemographics { get; set; } public virtual DbSet<Customer> Customers { get; set; } public virtual DbSet<Employee> Employees { get; set; } public virtual DbSet<Order_Detail> Order_Details { get; set; } public virtual DbSet<Order> Orders { get; set; } public virtual DbSet<Product> Products { get; set; } public virtual DbSet<Region> Regions { get; set; } public virtual DbSet<Shipper> Shippers { get; set; } public virtual DbSet<Supplier> Suppliers { get; set; } public virtual DbSet<Territory> Territories { get; set; } } }
好了,至此,EntityFramework的基本概念和Database First基本操作已经完成,由于水平有限,如果在讲解过程中有任何错误请留言告知,在学习与记录的过程与大家共同进步。下一篇会讲解EntityFramework的Model First。