Entity Framework中的连接管理
EF框架对数据库的连接提供了一系列的默认行为,通常情况下不需要我们太多的关注。但是,这种封装,降低了灵活性,有时我们需要对数据库连接加以控制。
EF提供了两种方案控制数据库连接:
- 传递到Context的连接;
- Database.Connnection.Open();
下面详解。
传递到Context的连接
EF6之前版本
有两个接受Connection的构造方法:
public DbContext(DbConnection existingConnection, bool contextOwnsConnection)
public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
使用上面两个方法的时候需要注意的限制:
1、如果使用上面任意一个方法,传递了一个已经打开的连接,则会在首次使用EF操作数据库时抛出一个InvalidOperationException异常,表示不能重复打开一个链接;
2、contextOwnsConnection参数指示在DbContext对象Dispose时候是否Dispose底层的数据库连接。无论参数是否设置,在DbContext.Dispose()时都会关闭底层的Connection。所以,如果你有超过一个DbContext使用同一连接,其中任何一个DbContext对象Dispose时都会关闭该连接(类似的,如果你将ADO.NET 和DbContext对象混合使用,在DbContect对象Dispose时也会关闭连接)。
可以通过传递一个关闭的连接,在创建的上下文中仅打开一次连接,且仅执行代码绕过上面第一条限制。如下:
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient;
using System.Linq; namespace ConnectionManagementExamples
{
class ConnectionManagementExampleEF5
{
public static void TwoDbContextsOneConnection()
{
using (var context1 = new BloggingContext())
{
var conn =
((EntityConnection)
((IObjectContextAdapter)context1).ObjectContext.Connection)
.StoreConnection; using (var context2 = new BloggingContext(conn, contextOwnsConnection: false))
{
context2.Database.ExecuteSqlCommand(
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'"); var query = context1.Posts.Where(p => p.Blog.Rating > );
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context1.SaveChanges();
}
}
}
}
}
第二个限制仅仅意味着你要确保确实要关闭连接后再调用DbContext.Dispose()。
EF6版本及更新版本
EF6和将来的版本的DbContext有两个与以往版本相同重载的构造方法,但是不在要求传递一个关闭的连接了。所以下面代码在EF6及以后版本是正确的:
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions; namespace ConnectionManagementExamples
{
class ConnectionManagementExample
{
public static void PassingAnOpenConnection()
{
using (var conn = new SqlConnection("{connectionString}"))
{
conn.Open(); var sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.CommandText =
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'";
sqlCommand.ExecuteNonQuery(); using (var context = new BloggingContext(conn, contextOwnsConnection: false))
{
var query = context.Posts.Where(p => p.Blog.Rating > );
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges();
} var sqlCommand2 = new SqlCommand();
sqlCommand2.Connection = conn;
sqlCommand2.CommandText =
@"UPDATE Blogs SET Rating = 7" +
" WHERE Name LIKE '%Entity Framework Rocks%'";
sqlCommand2.ExecuteNonQuery();
}
}
}
}
还有,现在contextOwnsConnection参数决定是否要在DbContext对象Dispose时关闭并Dispose连接对象。因此,上面代码,在DbContext对象Dispose时,数据库并未关闭(32行),但在以前的版本在此处会关闭连接。上面代码会在第40行关闭并释放。
当然,如果你仍然可以让DbContext对象控制连接,把contextOwnsConnection设置为true,或者使用另一个构造方法。
Database.Connnection.Open()
EF6以前的版本
EF5及之前版本ObjectionContext.Connection.State状态更新存在BUG,该值不能正确反映底层连接的状态。例如执行下面代码,获取的状态为Closed,即使其底层确实为Open:
((IObjectContextAdapter)context).ObjectContext.Connection.State
另外,如果你通过调用Database.Connection.Open()打开数据库连接,数据库连接将一直打开,直到执行下次执行一个查询或者任何请求连接的操作(例如SaveChanges)。但是在此之后底层连接将会被关闭。那么Context将会因任意的数据库操作而重新打开连接并在之后重新关闭:
using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient; namespace ConnectionManagementExamples
{
public class DatabaseOpenConnectionBehaviorEF5
{
public static void DatabaseOpenConnectionBehavior()
{
using (var context = new BloggingContext())
{
// At this point the underlying store connection is closed context.Database.Connection.Open(); // Now the underlying store connection is open
// (though ObjectContext.Connection.State will report closed) var blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog); // The underlying store connection is still open context.SaveChanges(); // After SaveChanges() the underlying store connection is closed
// Each SaveChanges() / query etc now opens and immediately closes
// the underlying store connection blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
context.SaveChanges();
}
}
}
}
EF6及将来版本
在EF6和将来的版本中,框架采用的方案是如果代码通过context.Database.Connection.Open()打开一个数据库连接,有理由相信代码想要自己控制连接的打开和关闭,框架将不再自动关闭连接。
注意:这一特性可能造成数据库连接长时间打开,所以要特别留意,防止连接未及时关闭。
EF6中修复了ObjectContext.Connection.State状态更新的BUG。
using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Infrastructure; namespace ConnectionManagementExamples
{
internal class DatabaseOpenConnectionBehaviorEF6
{
public static void DatabaseOpenConnectionBehavior()
{
using (var context = new BloggingContext())
{
// At this point the underlying store connection is closed context.Database.Connection.Open(); // Now the underlying store connection is open and the
// ObjectContext.Connection.State correctly reports open too var blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
context.SaveChanges(); // The underlying store connection remains open for the next operation blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
context.SaveChanges(); // The underlying store connection is still open } // The context is disposed – so now the underlying store connection is closed
}
}
}
Entity Framework中的连接管理的更多相关文章
- Entity Framework 6 Database-first连接Oracle11g
Entity Framework 6 Database-first连接Oracle11g(图文细说) 本文发布地址:http://www.cnblogs.com/likeli/p/5577264.ht ...
- 在Entity Framework中重用现有的数据库连接字符串
本文转载:http://www.cnblogs.com/dudu/archive/2011/01/29/entity_framework_connection_string.html 如果EF在使用实 ...
- 在Entity Framework 中实现继承关系映射到数据库表
继承关系映射到数据库表中有多种方式: 第一种:TPH(table-per-hiaerachy) 每一层次一张表 (只有一张表) 仅使用名为父类的类型名的一张表,它包含了各个子类的所有属性信息,使用区分 ...
- Entity Framework 教程——Entity Framework中的实体类型
Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...
- 关于Entity Framework中的Attached报错相关解决方案的总结
关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...
- 关于Entity Framework中的Attached报错的完美解决方案终极版
之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...
- [转]在Entity Framework中使用LINQ语句分页
本文转自:http://diaosbook.com/Post/2012/9/21/linq-paging-in-entity-framework 我们知道,内存分页效率很低.并且,如果是WebForm ...
- 在Entity Framework中使用事务
继续为想使用Entity Framework的朋友在前面探路,分享的东西虽然技术含量不高,但都是经过实践检验的. 在Entity Framework中使用事务很简单,将操作放在TransactionS ...
- Entity Framework中的多个库操作批量提交、事务处理
在Entity Framework 中使用SaveChanges()是很频繁的,单次修改或删除数据后调用SaveChanges()返回影响记录数. 要使用批量修改或者批量删除数据,就需要SaveCha ...
随机推荐
- 我的Linux之路——xshell连接linux虚拟机
出自:https://www.linuxidc.com/Linux/2016-08/134087.htm xshell 5登录本地虚拟机的具体操作步骤如下: 1.首先打开虚拟机,登录到操作系统; 2. ...
- 谈谈跨平台的app开发 坚定的选择了flutter
目前市场上,(市场也许用的不对),比较常见的技术有xamrin.RN.Flutter,确切的说flutter是后起之秀,笔者也是最近才开始学习,xamrin是微软系的技术,笔者也很早就开始学习了,RN ...
- ServletContextListener中@Autowired失效的解决方法
@WebListener public class ContextWebListener implements ServletContextListener { @Override public vo ...
- MongoDB常用增删改查语句
数据库database 创建及查看库 1.有则使用这个数据库,没有就创建 use DATABASE_NAME 2. 查看当前选择的数据库,默认是test db 3.查看数据库,默认有admin.loc ...
- 【CodeForces148D】Bag of mice
题意 dragon和princess玩一个游戏.开始的时候袋子里有w个白老鼠和b个黑老鼠.两个人轮流从袋子里面往外摸老鼠.谁先拿到白老鼠谁先获胜.dragon每次抓出一只老鼠,剩下老鼠里面都会有一只跳 ...
- Computer2
luo@luo-All-Series:~/MyFile/TensorflowProject$ conda create -n flappbird1 python=3.7Solving environm ...
- 读取mysq数据库l数据,并使用dataview显示
来自<sencha touch权威指南>,约198页开始 通过php脚本,可以将mysql数据库的数据作为json数据格式进行读取. (1)php代码(bookinfo.php): < ...
- Mac os安装DVWA环境教程
Mac os安装DVWA环境教程 1.尽管Mac自带Apache和php 事实上Mac和WIN都用XAMPP一键化安装比较方便 2.解压DVWA-master 改名为dvwa移动到XAMPP的目录 3 ...
- myeclipse如何取消对某个文件的验证
在用Myeclipse导入新工程或在写代码时,最郁闷的就是它对js,jsp,html的验证太严格了,有时会呈现一个红叉或者一个黄色的感慨号,一运行就报Cannot return from outsid ...
- Yii2 集成 adminlteasset
https://github.com/dmstr/yii2-adminlte-asset AdminLTE Asset Bundle Backend UI for Yii2 Framework, ba ...