净水机企业网站源码,wordpress 安卓 管理,程序员开发软件被拿去违法,怎么用一个主机做多个网站Entity Framework 6以前#xff0c;框架本身并没有提供显式的事务处理方案#xff0c;在EF6中提供了事务处理的API。 所有版本的EF#xff0c;只要你调用SaveChanges方法进行插入、修改或删除#xff0c;EF框架会自动将该操作进行事务包装。这种方法无法对事务进行显式的控… Entity Framework 6以前框架本身并没有提供显式的事务处理方案在EF6中提供了事务处理的API。 所有版本的EF只要你调用SaveChanges方法进行插入、修改或删除EF框架会自动将该操作进行事务包装。这种方法无法对事务进行显式的控制例如新建事务等可能会造成事务的粒度非常大降低效率。EF不会对查询进行事务包装。 从EF6开始默认情况下如果每次调用Database.ExecuteSqlCommand()如果其不在存在于任何事务中则会将该Command包装到一个事务中。框架提供了多种重载允许你重写这些方法实现事务的控制。同样执行存储过程的ObjectContext.ExecuteFunction()方法是实现了这种机制但是ExecuteFunction不能被重写。这两种情况下使用的事务隔离级别均为数据库提供的默认隔离级别SQL Server中使用的是READ COMMITED。 有同学提供了EF6之前版本的事务方案如下 1 using (BlogDbContext context new BlogDbContext())2 {3 using (TransactionScope transaction new TransactionScope())4 {5 context.BlogPosts.Add(blogPost);6 context.SaveChanges();7 postBody.ID blogPost.ID;8 context.EntryViewCounts.Add(9 new EntryViewCount() { EntryID blogPost.ID });
10 context.PostBodys.Add(postBody);
11 context.SaveChanges();
12 //提交事务
13 transaction.Complete();
14 }
15 } 其实上面方法执行结果不会错但是存在隐患这样情况下显式事务其实是多余的。所以我对这种方案持怀疑态度没有进行内部代码的分析有时间了分析下希望大家拍砖。 官方体统的解决方案为 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 TransactionsExamples 8 { 9 class TransactionsExample
10 {
11 static void UsingTransactionScope()
12 {
13 using (var scope new TransactionScope(TransactionScopeOption.Required))
14 {
15 using (var conn new SqlConnection(...))
16 {
17 conn.Open();
18
19 var sqlCommand new SqlCommand();
20 sqlCommand.Connection conn;
21 sqlCommand.CommandText
22 UPDATE Blogs SET Rating 5
23 WHERE Name LIKE %Entity Framework%;
24 sqlCommand.ExecuteNonQuery();
25
26 using (var context
27 new BloggingContext(conn, contextOwnsConnection: false))
28 {
29 var query context.Posts.Where(p p.Blog.Rating 5);
30 foreach (var post in query)
31 {
32 post.Title [Cool Blog];
33 }
34 context.SaveChanges();
35 }
36 }
37
38 scope.Complete();
39 }
40 }
41 }
42 } 一般情况下用户不需要对事务进行特殊的控制使用EF框架默认行为即可。如果要对细节进行控制参考下面章节
EF6 API工作机制
EF6以前版本EF框架自己管理数据库连接如果你自己尝试打开连接可能会抛出异常打开一个已打开的连接会抛出异常。由于事务必须在一个打开的连接上执行因此要合并一系列操作到一个事务中要么使用TractionScope要么使用ObjectContext.Connection属性直接执行EntityConnection的Open()并BeginTransaction()。另外如果你在数据库底层连接上执行了事务上面API会失败。
注意EF6中移除了仅接受关闭连接的限制。
EF6 开始提供了
Database.BeginTransaction() : 为用户提供一种简单易用的方案在DbContext中启动并完成一个事务 -- 合并一系列操作到该事务中。同时使用户更方便的指定事务隔离级别。
Database.UseTransaction() : 允许DbContext使用一个EF框架外的事务。
在同一DbContext中合并一系列操作到一个事务中
Database.BeginTransaction()有两个重载方法。一个方法提供一个IsolationLevel参数另一个无参方法使用底层数据库提供程序默认的数据库事务隔离级别。两个重载方法均返回一个DbContextTransaction对象该对象提供Commit和Rollback方法用于数据库底层事务的提交和回滚。
使用DbContextTransaction意味着一旦提交或回滚事务就要释放该对象。一种简单的方法是使用using语法在using代码块结束时自动调用该对象的Dispose方法。 1 using System; 2 using System.Collections.Generic; 3 using System.Data.Entity; 4 using System.Data.SqlClient; 5 using System.Linq; 6 using System.Transactions; 7 8 namespace TransactionsExamples 9 {
10 class TransactionsExample
11 {
12 static void StartOwnTransactionWithinContext()
13 {
14 using (var context new BloggingContext())
15 {
16 using (var dbContextTransaction context.Database.BeginTransaction())
17 {
18 try
19 {
20 context.Database.ExecuteSqlCommand(
21 UPDATE Blogs SET Rating 5
22 WHERE Name LIKE %Entity Framework%
23 );
24
25 var query context.Posts.Where(p p.Blog.Rating 5);
26 foreach (var post in query)
27 {
28 post.Title [Cool Blog];
29 }
30
31 context.SaveChanges();
32
33 dbContextTransaction.Commit();
34 }
35 catch (Exception)
36 {
37 dbContextTransaction.Rollback();
38 }
39 }
40 }
41 }
42 }
43 } 注意启动一个事务需要底层数据库连接已打开。因此如果连接未打开调用Database.BeginTransaction()会打开连接在其Dispose时关闭连接。
传递一个现有事务到DbContext 有时你可能需要在同一数据库上执行一个EF框架之外更大范围的事务这是就需要自己打开连接并启动事务然后通知EF框架
1 使用已打开的数据库连接
2 在该连接上使用现有的事务 要实现上面的行为你需要使用继承自DbContext的构造方法XXXContext(conn,contextOwnsConnection)其中 conn 是一个已存在的数据库连接 contextOwnsConnection 是一个布尔值指示上下文是否自己占用数据库连接。
注意这种情况下contextOwnsConnection必须设置为false因为它通知EF框架在自己使用完连接后不要关闭它。见下面代码 1 using (var conn new SqlConnection(...))
2 {
3 conn.Open();
4 using (var context new BloggingContext(conn, contextOwnsConnection: false))
5 {
6 }
7 } 此外你必须自己启动事务如果你不想使用默认IsolationLevel可以自己设置之并让EF框架知道该连接上已经存在已启动的事务参考下面代码的33行。 然后就可以直接在连接上执行数据库操作或者在DbContext上执行所有这些操作均在同一事务中执行你负责提交或回滚事务并调用DatabaseTransaction.Dispose()最后要关闭和释放数据库连接。请参考以下代码 1 using System; 2 using System.Collections.Generic; 3 using System.Data.Entity; 4 using System.Data.SqlClient; 5 using System.Linq; 6 sing System.Transactions; 7 8 namespace TransactionsExamples 9 {
10 class TransactionsExample
11 {
12 static void UsingExternalTransaction()
13 {
14 using (var conn new SqlConnection(...))
15 {
16 conn.Open();
17
18 using (var sqlTxn conn.BeginTransaction(System.Data.IsolationLevel.Snapshot))
19 {
20 try
21 {
22 var sqlCommand new SqlCommand();
23 sqlCommand.Connection conn;
24 sqlCommand.Transaction sqlTxn;
25 sqlCommand.CommandText
26 UPDATE Blogs SET Rating 5
27 WHERE Name LIKE %Entity Framework%;
28 sqlCommand.ExecuteNonQuery();
29
30 using (var context
31 new BloggingContext(conn, contextOwnsConnection: false))
32 {
33 context.Database.UseTransaction(sqlTxn);
34
35 var query context.Posts.Where(p p.Blog.Rating 5);
36 foreach (var post in query)
37 {
38 post.Title [Cool Blog];
39 }
40 context.SaveChanges();
41 }
42
43 sqlTxn.Commit();
44 }
45 catch (Exception)
46 {
47 sqlTxn.Rollback();
48 }
49 }
50 }
51 }
52 }
53 } 注意
你可以传递null到方法Database.UseTransaction()来清除EF框架对当前事务的记忆。如果你这样做事务既不会提交也不会回滚。所以要谨慎使用之除非你确实需要这样。如果EF框架已经持有一个事务此时你传递一个事务Database.UseTransaction()将抛出一个异常★ EF框架已经持有一个事务 ★ 当EF框架已经在一个TransactionScope中运行 ★ 其数据库连接对象为null 例如无连接--通常这种情况表示事务已经完成 ★ 数据库连接对象与EF框架的数据库连接对象不匹配 对TransactionScope的一些补充
如果你使用.net framework 4.5.1及以上版本可以使用TransactionScope的TransactionScopeAsyncFlowOption参数提供对异步的支持 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 TransactionsExamples 8 { 9 class TransactionsExample
10 {
11 public static void AsyncTransactionScope()
12 {
13 using (var scope new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
14 {
15 using (var conn new SqlConnection(...))
16 {
17 await conn.OpenAsync();
18
19 var sqlCommand new SqlCommand();
20 sqlCommand.Connection conn;
21 sqlCommand.CommandText
22 UPDATE Blogs SET Rating 5
23 WHERE Name LIKE %Entity Framework%;
24 await sqlCommand.ExecuteNonQueryAsync();
25
26 using (var context new BloggingContext(conn, contextOwnsConnection: false))
27 {
28 var query context.Posts.Where(p p.Blog.Rating 5);
29 foreach (var post in query)
30 {
31 post.Title [Cool Blog];
32 }
33
34 await context.SaveChangesAsync();
35 }
36 }
37 }
38 }
39 }
40 } 目前使用TransactionScope还有一些限制
需要.NET 4.5.1及以上版本才支持异步方法不能适用于云方案除非你确保只有一个连接 -- 云方案不支持分布式事务不能和Database.UseTransaction()结合使用如果你的DDL代码存在问题例如数据库初始化问题或没有通过MSDTC服务来支持分布式事务将抛出异常
使用TransactionScope的优点
自动将本地事务升级为分布式事务前提是你有不止一个连接到给定数据库或要组合一个连接到另一个数据库连接到同一事务注意你必须启动MSDTC服务以支持分布式事务。易于编程。如果你更希望淡化对事务的关注而非显示操作事务使用TransactionScope将是一个更合适的选择。随着EF6提供了Database.BeginTransaction()和Database.UseTransaction() 两个API使用TransactionScope不在是必须的了。如果你依然使用TransactionScope就必须留意上面限制。建议你尽可能使用新的API而非TransactionScope。