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 ...
随机推荐
- python算法之选择排序
选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大 ...
- 好一个Time_Wait状态(TCP/IP)
首先简单介绍一下Time_Wait是个什么鬼: 在TCP/IP协议中,我们都知道有三次握手四次挥手的过程,先来一个简单的图: 各个状态和基本的过程想必了解过TCP/IP协议的人都清楚,本次介绍的主题只 ...
- 通过maven自动修改idea的compiler
Idea在使用过程中,经常会自动修改compiler水平,有时会变成jdk1.5,不支持@override,也不能忽略实例化的泛型参数,更不支持try-with-resource. 版本太低,很多特性 ...
- [cogs2638]数列操作ψ(双标记线段树)
题目大意:给定一个数列a,你需要支持的操作:区间and,区间or,询问区间最大值 解题关键: 1.双标记线段树,注意优先级(超时) 当涉及多重标记时,定义出标记的优先级,修改操作时用优先级高(先下放) ...
- Java中文乱码解决方案
Java中文乱码解决方案 1.中文乱码解决方案,确保每个文件的默认编码是UTF-8 加入 URIEncoding="UTF-8" 代码中的设置 1>在se ...
- javascript的Undefined,null区别
//在javascript中null表示“什么都没有” ,是一个特殊的类型,表示一个空对象引用: var person = null; //值为null(空),但类型为对象 console.log(p ...
- 访问tomcat出现java.lang.IllegalStateException No output folder错误解决方法
访问tomcat出现java.lang.IllegalStateException: No output folder错误解决方法 问题:tomcat分为安装版和解压缩版,解压缩版如果解压到安装盘,在 ...
- 数字图像处理:基于MATLAB的车牌识别项目 标签: 图像处理matlab算法 2017-06-24 09:17 98人阅读 评论(0)
学过了数字图像处理,就进行一个综合性强的小项目来巩固一下知识吧.前阵子编写调试了一套基于MATLAB的车牌识别的项目的代码.今天又重新改进了一下代码,识别的效果好一点了,也精简了一些代码.这里没有使用 ...
- Python和JavaScript间代码转换4个工具
Python 还是 JavaScript?虽然不少朋友还在争论二者目前谁更强势.谁又拥有着更为光明的发展前景,但毫无疑问,二者的竞争在 Web 前端领域已经拥有明确的答案.立足于浏览器平台,如果放弃 ...
- JMS学习之理论基础
本文代码使用ActiveMq5.6 一.什么是JMS JMS(Java Message Service,Java消息服务)是一组Java应用程序接口(Java API),它提供创建.发送.接收.读取消 ...