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. 我的Linux之路——xshell连接linux虚拟机

    出自:https://www.linuxidc.com/Linux/2016-08/134087.htm xshell 5登录本地虚拟机的具体操作步骤如下: 1.首先打开虚拟机,登录到操作系统; 2. ...

  2. 谈谈跨平台的app开发 坚定的选择了flutter

    目前市场上,(市场也许用的不对),比较常见的技术有xamrin.RN.Flutter,确切的说flutter是后起之秀,笔者也是最近才开始学习,xamrin是微软系的技术,笔者也很早就开始学习了,RN ...

  3. ServletContextListener中@Autowired失效的解决方法

    @WebListener public class ContextWebListener implements ServletContextListener { @Override public vo ...

  4. MongoDB常用增删改查语句

    数据库database 创建及查看库 1.有则使用这个数据库,没有就创建 use DATABASE_NAME 2. 查看当前选择的数据库,默认是test db 3.查看数据库,默认有admin.loc ...

  5. 【CodeForces148D】Bag of mice

    题意 dragon和princess玩一个游戏.开始的时候袋子里有w个白老鼠和b个黑老鼠.两个人轮流从袋子里面往外摸老鼠.谁先拿到白老鼠谁先获胜.dragon每次抓出一只老鼠,剩下老鼠里面都会有一只跳 ...

  6. Computer2

    luo@luo-All-Series:~/MyFile/TensorflowProject$ conda create -n flappbird1 python=3.7Solving environm ...

  7. 读取mysq数据库l数据,并使用dataview显示

    来自<sencha touch权威指南>,约198页开始 通过php脚本,可以将mysql数据库的数据作为json数据格式进行读取. (1)php代码(bookinfo.php): < ...

  8. Mac os安装DVWA环境教程

    Mac os安装DVWA环境教程 1.尽管Mac自带Apache和php 事实上Mac和WIN都用XAMPP一键化安装比较方便 2.解压DVWA-master 改名为dvwa移动到XAMPP的目录 3 ...

  9. myeclipse如何取消对某个文件的验证

    在用Myeclipse导入新工程或在写代码时,最郁闷的就是它对js,jsp,html的验证太严格了,有时会呈现一个红叉或者一个黄色的感慨号,一运行就报Cannot return from outsid ...

  10. Yii2 集成 adminlteasset

    https://github.com/dmstr/yii2-adminlte-asset AdminLTE Asset Bundle Backend UI for Yii2 Framework, ba ...