一、引言
前面几篇EF Core相关的学习笔记讲了不少EF Core中概念性的东西,但没有实际编程操作过。
这篇算是开始简单使用DbContext的基本功能。相信通过前面文章对实体、上下文、数据标注这些基本概念有一定了解后,能很快地上手使用DbContext来访问数据。如果对这些概念没有太多了解也没事,因为本文是偏应用型的。
注意:
本文在微软文档中是属于EF6节点下的介绍的。
但对于上下文这种基础的部分来讲,EF Core和EF6是没有太大差异的,可以认为等同,所以完全可以当EF Core的内容来看。
二、过程
那么为了使用EF来操作.NET对象进行查询、插入、更新和删除数据,首先需要创建一个Model,这个Model将定义在其中的实体和关系映射到数据库中的表上。
一旦你有了一个Model,与应用程序交互的基本类就是System.Data.Entity.DbContext(通常称其为上下文类)。
为什么有了Model,与程序交互的类就变成了上下文???
第一篇文章就讲过了,Model是由实体和上下文组成的。它不是一个类,它是一套东西。
而其中与数据库交互的就是上下文。
你可以使用与Model关联的上下文来做以下事情:
- 写&查询数据
- 将查询结果转化为实体对象(原来你用SQL语句查询的结果可能是个什么类型的集合啊,而用model查询得到的还是一个实体对象,可以用各种便捷的方法操作)
- 追踪这些对象上的改变
- 将对象的更改持久化到数据库中
- 绑定内存中的对象到UI控件上
接下来会提供一些如何管理上下文的指导。
1. 定义一个DbContext的派生类
使用上下文比较推荐的方式是定义一个DbContext的派生类,并且公开(暴露)表示上下文中指定实体集合的DbSet属性。如果你使用了EF设计器,环境会为你生成这些的。如果你是先用代码来实现,那你往往会自己来编写上下文:
public class ProductContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
一旦有了一个上下文,你就可以通过这些暴露在其中的属性来查询、添加(使用Add或Attach方法)或移除(使用Remove)上下文中的实体。
这边说的实体,在关系数据库中可以认为是表(关系)中的一行(一条记录/一个元组)。
所以有了上下文,并且关联了实体之后,你就可以通过上下文对象来操作数据表了。
访问上下文对象上的DbSet属性表示进行查询,该查询会返回指定类型的所有实体(符合查询条件的所有记录转化为实体对象)。注意,仅仅访问一个属性是不会执行查询的。在以下情况下查询会执行:
- 由foreach(C#)或For Each(VB)语句枚举。
- 由ToArray、ToDictionary或ToList等集合操作枚举。
- 在查询最外层部分指定LINQ操作符(如First或Any)。
- 以下方法之一被调用:
- Load拓展方法
- DbEntityEntry.Reload
- Database.ExecuteSqlCommand
- DbSet<T>.Find
如果在上下文中未找到已经加载的带有指定键的实体。
*2. 生命周期
这小节蛮重要的,与实际使用的合理性有关。
上下文的生命周期始于实例创建时,终于实例被处理(Dispose)或GC回收。如果你想在块的末尾释放上下文控制的所有资源,请使用using。当你使用using时,编译器会自动创建一个try/finally块,并在finally块中调用dispose。
这部分知识可以看C#中的using关键字的语句用法
不想花太多时间,可以只了解用法即可。
public void UseProducts()
{
using (var context = new ProductContext())
{
// 使用上下文进行数据访问
}
}
在决定上下文的生命周期时,以下是一些一般准则(请结合场景仔细考虑):
- 当使用Web应用程序时,对每个请求使用一个上下文实例。
- 在使用WPF或者WinForms时,请为每个窗体使用一个上下文实例。这允许你使用上下文提供更改跟踪功能。
- 如果上下文实例是由依赖项注入容器创建的,那么释放上下文通常是容器的责任。
- 如果上下文是在应用程序代码(App)中创建的,记得在不再需要它时释放掉。
- 当使用长时间运行的上下文时,请考虑以下几点:
- 随着你加载更多对象和它们的引用到内存中,上下文的内存消耗可能会迅速增加。这可能会导致一些性能问题。
- 上下文不是线程安全的,因此它不应该在多个线程之间同时进行操作。
- 如果一个异常导致了上下文陷入了不可修复的状态,整个应用程序可能会终止。
- 随着查询和更新数据的时间间隔增加,遇到并发相关问题的几率也会增加。
3. 连接
默认情况下,上下文管理着与数据库的连接。上下文根据需要开关连接。例如,上下文打开一个连接来执行一次查询,然后在处理完所有结果集后关闭该连接。
可能在某些情况下,你希望对连接的开关时间有更多的控制。例如,在使用SQL Server Compact时,通常建议在应用程序的生命周期内维持一个单独的数据库打开连接,以提高性能。你可以使用Connection属性来手动管理此过程。
三、结尾
微软官方文档对EF Core的描述还是偏概念的,感觉是为有EF基础的人准备的。所以对于初学者我觉得看EF部分的文档是个不错的选择。