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中的连接管理的更多相关文章

  1. Entity Framework 6 Database-first连接Oracle11g

    Entity Framework 6 Database-first连接Oracle11g(图文细说) 本文发布地址:http://www.cnblogs.com/likeli/p/5577264.ht ...

  2. 在Entity Framework中重用现有的数据库连接字符串

    本文转载:http://www.cnblogs.com/dudu/archive/2011/01/29/entity_framework_connection_string.html 如果EF在使用实 ...

  3. 在Entity Framework 中实现继承关系映射到数据库表

    继承关系映射到数据库表中有多种方式: 第一种:TPH(table-per-hiaerachy) 每一层次一张表 (只有一张表) 仅使用名为父类的类型名的一张表,它包含了各个子类的所有属性信息,使用区分 ...

  4. Entity Framework 教程——Entity Framework中的实体类型

    Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...

  5. 关于Entity Framework中的Attached报错相关解决方案的总结

    关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...

  6. 关于Entity Framework中的Attached报错的完美解决方案终极版

    之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...

  7. [转]在Entity Framework中使用LINQ语句分页

    本文转自:http://diaosbook.com/Post/2012/9/21/linq-paging-in-entity-framework 我们知道,内存分页效率很低.并且,如果是WebForm ...

  8. 在Entity Framework中使用事务

    继续为想使用Entity Framework的朋友在前面探路,分享的东西虽然技术含量不高,但都是经过实践检验的. 在Entity Framework中使用事务很简单,将操作放在TransactionS ...

  9. Entity Framework中的多个库操作批量提交、事务处理

    在Entity Framework 中使用SaveChanges()是很频繁的,单次修改或删除数据后调用SaveChanges()返回影响记录数. 要使用批量修改或者批量删除数据,就需要SaveCha ...

随机推荐

  1. 在Ubuntu 16.04如何安装Java使用apt-get的

    转自:https://www.howtoing.com/how-to-install-java-with-apt-get-on-ubuntu-16-04/ 的Java和JVM(Java的虚拟机)是广泛 ...

  2. Oracle 与 MySQL 批量添加

    Oracle: <update id="createNew" statementType="STATEMENT" parameterType=" ...

  3. Coursera连接不上(视频无法播放),修改hosts文件

    视频问题 如果Coursera网站连接不上,或者视频加载不出来.可以通过如下方式进行配置:   一.找到hosts文件 Windows 系统, hosts文件位于: [C:\Windows\Syste ...

  4. How to map host ip and port to Hyper-V

    1.1       Add an port proxy netsh interface portproxy add v4tov4 listenport=hostport listenaddres=ho ...

  5. SaltStack 的通讯及安全机制

    SaltStack 的通讯架构模型: Salt 采用服务端-代理的通讯模型(也可以通过 SSH 方式实现非代理模式).服务端称为 Salt master,代理端称为 Salt minion. Salt ...

  6. redis入门资源收集汇总

    redis安装:http://www.redis.io/download redis命令测试平台:http://try.redis.io/ redis桌面管理工具:http://redisdeskto ...

  7. Quaternion.identity是什么意思?

    Quaternion.identity就是指Quaternion(0,0,0,0),

  8. Git,GitHub以及GitLab的区别

    Git - 版本控制工具 Github - 一个网站,提供给用户空间创建git仓储,保存用户的一些数据文档或者代码等 GitLab - 基于Git的项目管理软件 Git分布式版本控制系统 Git是一款 ...

  9. mysql数据库优化总结 有图 有用

    对于一个以数据为中心的应用,数据库的好坏直接影响到程序的性能,因此数据库性能至关重要.一般来说,要保证数据库的效率,要做好以下四个方面的工作:数据库设计.sql语句优化.数据库参数配置.恰当的硬件资源 ...

  10. Linux系统巡检常用命令-乾颐堂

    Linux系统需要定期巡检,以检查服务器软硬件使用情况,相当于对人的体检,确保可以及时发现问题.解决问题,降低损失,常用的巡检命令如下: # uname -a # 查看内核/操作系统/CPU信息 # ...