什么是EF
EF是一种ORM(Object-relational mapping)框架,它能把我们在编程时使用对象映射到底层的数据库结构。它可以让应用程序开发者将关系型数据作为业务模型来使用,也消除了开发者为数据访问编写的绝大多数管道代码的需要(比如使用ADO.NET)。Entity Framework提供了一个综合的、基于模型的系统,通过为所有的领域模型编写相似的数据访问代码,使得开发者创建数据访问层变得简单
EF优点
- 之前需要花费大量的时间来编写将数据保存到数据库的代码,EF极大的减少了这段时间
- 将重点放在业务上,而无需担心这些数据的存储
- 减少代码量提高生产系效率,同时也使得程序更容易维护
- ...
EF三种开发方式
Code First
所有的领域模型都是以类的形式编写的。这些类会建立我们的EDM,数据库模式会从这些类中创建。这种方法最适合于那些高度以领域为中心并且领域模型类创建优先的应用程序。这里需要的数据库只是为了这些领域模型的持久化机制。
- 数据库只是作为模型的持久化机制,即数据库中没有逻辑
- 完全控制代码,即没有自动生成的模型和上下文代码
- 数据库不会手动更改。模型类总是更改,然后数据库基于模型类的更改而更改
Database First
这是一种用于已存在数据库模式的方法。使用这种方法,EDM是从数据库模式中生成的,这种方法最适合于使用了已经存在的数据库的应用。
- 对遗留的数据库进行开发
- 当其他团队的DBA完成了数据库设计时,一旦数据库完成,应用开发就要开始
- 当要开发数据为中心的应用时,应用领域模型就是数据库本身,数据库会频繁修改来满足新的需求
Model First
这种方法和Code First方法很相似,但是这种情况下我们使用了EDM视觉设计器来设计我们的模型。数据库模式和类将会通过这个概念模型生成。该模型将会给我们创建数据库的SQL语句,然后我们可以使用它来创建数据库并连接应用程序。
EF安装及开发方式选择
NuGet:Install-Package EntityFramework
之前说到EF支持三种开发方式,在开发时如何选择适合自己的方式
- 如果已经有了域类,Code-first,通过类创建数据库
- 如果已经有数据库,Database-first:根据现有的数据库生成对应实体类和EDM文件
- 如果喜欢使用视觉设计图的方式设计数据库模型,Model-first
DbContext
DbContext是EntityFramewoke的一个重要组成部分。 他是一个域或实体类和数据库之间的桥梁。主要负责与数据交互,派生的类DbContext称为实体框架的上下文类
- EntitySet: DbContext包含所有的实体映射到数据库表的实体集(DbSet<TEntity>)
- 查询: DbContext 将LINQ-to-Entities查询转换为SQL查询并将其发送到数据库
- 更改跟踪: 它跟踪每个实体从数据库中查询出来后发生的修改变化
- 持久化数据: 它也基于实体状态执行插入、更新和删除操作到数据库中
- 缓存: DbContext默认第一级缓存
- 对象实例化: DbContext将原始表数据转换成实体对象
上下文类覆盖OnModelCreating方法。 可以用来在Code-first开始模式中配置实体
DBSet
DbSet 表示上下文中给定类型的所有实体的集合或可从数据库中查询的给定类型的所有实体的集合.代表一个实体集,用于创建、读取、更新和删除操作,可以使用 DbContext.Set 方法从 DbContext 中创建 DbSet对象,常见的DbSet类的方法如下:
名称 | 描述 |
---|---|
Add | 将给定实体以“已添加”状态添加到集的基础上下文中,这样一来,当调用 SaveChanges 时,会将该实体插入到数据库中 |
AddRange | 将给定实体集合添加到基础化集的上下文中(每个实体都置于“已添加”状态),这样当调用 SaveChanges 时,会将它插入到数据库中 |
AsNoTracking | 返回一个新查询,其中返回的实体将不会在 DbContext 中进行缓存. (继承自 DbQuery) |
AsStreaming | 已过时. 返回将流式处理结果而非缓存它的新查询. (继承自 DbQuery<TResult>) |
Attach | 将给定实体附加到集的基础上下文中. 也就是说,将实体以“未更改”的状态放置到上下文中,就好像从数据库读取了该实体一样 |
Create | 为此集的类型创建新的实体实例. 请注意此实例不会添加或附加到此集. 如果基础上下文配置为创建代理且实体类型满足创建代理的要求,则返回的实例将是一个代理 |
Create<TDerivedEntity>() | 为此集的类型或派生自此集类型的类型创建新的实体实例. 请注意此实例不会添加或附加到此集. 如果基础上下文配置为创建代理且实体类型满足创建代理的要求,则返回的实例将是一个代理 |
Equals | 确定指定的 DbSet 是否等于当前 DbSet. (重写 DbQuery.Equals(Object)) |
Equals | 确定指定的 DbSet 是否等于当前 DbSet. (重写 DbQuery.Equals(Object).) |
Finalize | (继承自 Object.) |
Find | 查找带给定主键值的实体. 如果上下文中存在带给定主键值的实体,则立即返回该实体,而不会向存储区发送请求. 否则,会向存储区发送查找带给定主键值的实体的请求,如果找到该实体,则将其附加到上下文并返回.如果未在上下文或存储区中找到实体,则返回 null |
FindAsync | 异步查找带给定主键值的实体. 如果上下文中存在带给定主键值的实体,则立即返回该实体,而不会向存储区发送请求. 否则,会向存储区发送查找带给定主键值的实体的请求,如果找到该实体,则将其附加到上下文并返回. 如果未在上下文或存储区中找到实体,则返回 null |
GetHashCode | 异步查找带给定主键值的实体. 如果上下文中存在带给定主键值的实体,则立即返回该实体,而不会向存储区发送请求. 否则,会向存储区发送查找带给定主键值的实体的请求,如果找到该实体,则将其附加到上下文并返回. 如果未在上下文或存储区中找到实体,则返回 null |
GetType | 返回当前 DbSet 的类型 |
Include | 指定要包括在查询结果中的相关对象. (继承自 DbQuery) |
MemberwiseClone | (继承自 Object) |
Remove | 将给定实体标记为“已删除”,这样一来,当调用 SaveChanges 时,将从数据库中删除该实体. 请注意,在调用此方法之前,该实体必须以另一种状态存在于该上下文中 |
RemoveRange | 从基础化集的上下文中删除给定实体集合(每个实体都置于“已删除”状态),这样当调用 SaveChanges 时,会从数据库中删除它 |
SqlQuery | 创建一个原始 SQL 查询,该查询将返回此集中的实体. 默认情况下,上下文会跟踪返回的实体;可通过对返回的 DbSqlQuery 调用 AsNoTracking 来更改此设置. 请注意返回实体的类型始终是此集的类型,而不会是派生的类型. 如果查询的一个或多个表可能包含其他实体类型的数据,则必须编写适当的 SQL 查询以确保只返回适当类型的实体. 与接受 SQL 的任何 API 一样,对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的. 您可以在 SQL 查询字符串中包含参数占位符,然后将参数值作为附加参数提供. 您提供的任何参数值都将自动转换为 DbParameter. context.Blogs.SqlQuery("SELECT * FROM dbo.Posts WHERE Author = @p0", userSuppliedAuthor); 或者,您还可以构造一个 DbParameter 并将它提供给 SqlQuery. 这允许您在 SQL 查询字符串中使用命名参数. context.Blogs.SqlQuery("SELECT * FROM dbo.Posts WHERE Author = @author", new SqlParameter("@author", userSuppliedAuthor)) |
ToString | 返回基础查询的 String 表示形式. (继承自 DbQuery<TResult>) |
开发方式视应用场景而定,此系列笔记使用Code-First
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">