博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Entity Framework中的连接管理
阅读量:5335 次
发布时间:2019-06-15

本文共 7344 字,大约阅读时间需要 24 分钟。

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时也会关闭连接)。

可以通过传递一个关闭的连接,在创建的上下文中仅打开一次连接,且仅执行代码绕过上面第一条限制。如下:

1 using System.Collections.Generic;  2 using System.Data.Common;  3 using System.Data.Entity;  4 using System.Data.Entity.Infrastructure;  5 using System.Data.EntityClient;  6 using System.Linq;  7   8 namespace ConnectionManagementExamples  9 { 10     class ConnectionManagementExampleEF5 11     {         12         public static void TwoDbContextsOneConnection() 13         { 14             using (var context1 = new BloggingContext()) 15             { 16                 var conn = 17                     ((EntityConnection)  18                         ((IObjectContextAdapter)context1).ObjectContext.Connection)  19                             .StoreConnection; 20  21                 using (var context2 = new BloggingContext(conn, contextOwnsConnection: false)) 22                 { 23                     context2.Database.ExecuteSqlCommand( 24                         @"UPDATE Blogs SET Rating = 5" + 25                         " WHERE Name LIKE '%Entity Framework%'"); 26  27                     var query = context1.Posts.Where(p => p.Blog.Rating > 5); 28                     foreach (var post in query) 29                     { 30                         post.Title += "[Cool Blog]"; 31                     } 32                     context1.SaveChanges(); 33                 } 34             } 35         } 36     } 37 }

第二个限制仅仅意味着你要确保确实要关闭连接后再调用DbContext.Dispose()。

EF6版本及更新版本

EF6和将来的版本的DbContext有两个与以往版本相同重载的构造方法,但是不在要求传递一个关闭的连接了。所以下面代码在EF6及以后版本是正确的:

1 using System.Collections.Generic;  2 using System.Data.Entity;  3 using System.Data.SqlClient;  4 using System.Linq;  5 using System.Transactions;  6   7 namespace ConnectionManagementExamples  8 {  9     class ConnectionManagementExample 10     { 11         public static void PassingAnOpenConnection() 12         { 13             using (var conn = new SqlConnection("{connectionString}")) 14             { 15                 conn.Open(); 16  17                 var sqlCommand = new SqlCommand(); 18                 sqlCommand.Connection = conn; 19                 sqlCommand.CommandText = 20                     @"UPDATE Blogs SET Rating = 5" + 21                      " WHERE Name LIKE '%Entity Framework%'"; 22                 sqlCommand.ExecuteNonQuery(); 23  24                 using (var context = new BloggingContext(conn, contextOwnsConnection: false)) 25                 { 26                     var query = context.Posts.Where(p => p.Blog.Rating > 5); 27                     foreach (var post in query) 28                     { 29                         post.Title += "[Cool Blog]"; 30                     } 31                     context.SaveChanges(); 32                 } 33  34                 var sqlCommand2 = new SqlCommand(); 35                 sqlCommand2.Connection = conn; 36                 sqlCommand2.CommandText = 37                     @"UPDATE Blogs SET Rating = 7" + 38                      " WHERE Name LIKE '%Entity Framework Rocks%'"; 39                 sqlCommand2.ExecuteNonQuery(); 40             } 41         } 42     } 43 }

      还有,现在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将会因任意的数据库操作而重新打开连接并在之后重新关闭:

1 using System;  2 using System.Data;  3 using System.Data.Entity;  4 using System.Data.Entity.Infrastructure;  5 using System.Data.EntityClient;  6   7 namespace ConnectionManagementExamples  8 {  9     public class DatabaseOpenConnectionBehaviorEF5 10     { 11         public static void DatabaseOpenConnectionBehavior() 12         { 13             using (var context = new BloggingContext()) 14             { 15                 // At this point the underlying store connection is closed 16  17                 context.Database.Connection.Open(); 18  19                 // Now the underlying store connection is open  20                 // (though ObjectContext.Connection.State will report closed) 21  22                 var blog = new Blog { /* Blog’s properties */ }; 23                 context.Blogs.Add(blog); 24                  25                 // The underlying store connection is still open  26  27                 context.SaveChanges(); 28  29                 // After SaveChanges() the underlying store connection is closed  30                 // Each SaveChanges() / query etc now opens and immediately closes 31                 // the underlying store connection 32  33                 blog = new Blog { /* Blog’s properties */ }; 34                 context.Blogs.Add(blog); 35                 context.SaveChanges(); 36             } 37         } 38     } 39 }

 

EF6及将来版本

       在EF6和将来的版本中,框架采用的方案是如果代码通过context.Database.Connection.Open()打开一个数据库连接,有理由相信代码想要自己控制连接的打开和关闭,框架将不再自动关闭连接。

       注意:这一特性可能造成数据库连接长时间打开,所以要特别留意,防止连接未及时关闭。

       EF6中修复了ObjectContext.Connection.State状态更新的BUG。

1 using System;  2 using System.Data;  3 using System.Data.Entity;  4 using System.Data.Entity.Core.EntityClient;  5 using System.Data.Entity.Infrastructure;  6   7 namespace ConnectionManagementExamples  8 {  9     internal class DatabaseOpenConnectionBehaviorEF6 10     { 11         public static void DatabaseOpenConnectionBehavior() 12         { 13             using (var context = new BloggingContext()) 14             { 15                 // At this point the underlying store connection is closed 16  17                 context.Database.Connection.Open(); 18  19                 // Now the underlying store connection is open and the 20                 // ObjectContext.Connection.State correctly reports open too 21                  22                 var blog = new Blog { /* Blog’s properties */ }; 23                 context.Blogs.Add(blog); 24                 context.SaveChanges(); 25  26                 // The underlying store connection remains open for the next operation  27                     28                 blog = new Blog { /* Blog’s properties */ }; 29                 context.Blogs.Add(blog); 30                 context.SaveChanges(); 31  32                 // The underlying store connection is still open 33   34            } // The context is disposed – so now the underlying store connection is closed 35         } 36     } 37 }

 

转载于:https://www.cnblogs.com/from1991/p/5425018.html

你可能感兴趣的文章
Linux目录结构
查看>>
learning awk
查看>>
LeetCode-Strobogrammatic Number
查看>>
luoguP3414 SAC#1 - 组合数
查看>>
五一 DAY 4
查看>>
关于System.__ComObject一些问题
查看>>
java stringbuffer二
查看>>
[hihoCoder] 拓扑排序·一
查看>>
(转)接口测试用例设计(详细干货)
查看>>
js Math对象方法 (个人学习笔记)
查看>>
helm-chart-2-chart结构和简单模板
查看>>
转载Repository 和Unit of work的使用说明
查看>>
【译】SSH隧道:本地和远程端口转发
查看>>
win8.1安装Python提示缺失api-ms-win-crt-runtime-l1-1-0.dll问题
查看>>
图片点击轮播(三)-----2017-04-05
查看>>
判断两个字符串是否相等【JAVA】
查看>>
直播技术细节3
查看>>
《分布式服务架构:原理、设计于实战》总结
查看>>
java中new一个对象和对象=null有什么区别
查看>>
字母和数字键的键码值(keyCode)
查看>>