原文:https://msdn.microsoft.com/en-us/data/dn456843.aspx

Prior to EF6 Entity Framework insisted on opening the database connection itself (it threw an exception if it was passed a connection that was already open). Since a transaction can only be started on an open connection, this meant that the only way a user could wrap several operations into one transaction was either to use a TransactionScope or use the ObjectContext.Connection property and start calling Open() and BeginTransaction() directly on the returned EntityConnection object. In addition, API calls which contacted the database would fail if you had started a transaction on the underlying database connection on your own.

Note: The limitation of only accepting closed connections was removed in Entity Framework 6. For details, see Connection Management (EF6 Onwards).

Starting with EF6 the framework now provides:

  1. Database.BeginTransaction() : An easier method for a user to start and complete transactions themselves within an existing DbContext – allowing several operations to be combined within the same transaction and hence either all committed or all rolled back as one. It also allows the user to more easily specify the isolation level for the transaction.
  2. Database.UseTransaction() : which allows the DbContext to use a transaction which was started outside of the Entity Framework.

Combining several operations into one transaction within the same context

Database.BeginTransaction() has two overrides – one which takes an explicit IsolationLevel and one which takes no arguments and uses the default IsolationLevel from the underlying database provider. Both overrides return a DbContextTransaction object which provides Commit() and Rollback() methods which perform commit and rollback on the underlying store transaction.

The DbContextTransaction is meant to be disposed once it has been committed or rolled back. One easy way to accomplish this is the using(…) {…} syntax which will automatically call Dispose() when the using block completes:

static void StartOwnTransactionWithinContext()
{
using (var context = new BloggingContext())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
context.Database.ExecuteSqlCommand(
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'"
); var query = context.Posts.Where(p => p.Blog.Rating >= );
foreach (var post in query)
{
post.Title += "[Cool Blog]";
} context.SaveChanges(); dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
}
}

Note: Beginning a transaction requires that the underlying store connection is open. So calling Database.BeginTransaction() will open the connection  if it is not already opened. If DbContextTransaction opened the connection then it will close it when Dispose() is called.

Sometimes you would like a transaction which is even broader in scope and which includes operations on the same database but outside of EF completely. To accomplish this you must open the connection and start the transaction yourself and then tell EF a) to use the already-opened database connection, and b) to use the existing transaction on that connection.

To do this you must define and use a constructor on your context class which inherits from one of the DbContext constructors which take i) an existing connection parameter and ii) the contextOwnsConnection boolean.

Note: The contextOwnsConnection flag must be set to false when called in this scenario. This is important as it informs Entity Framework that it should not close the connection when it is done with it (e.g. see line 4 below):

using (var conn = new SqlConnection("...")) 

    conn.Open(); 
    using (var context = new BloggingContext(conn, contextOwnsConnection: false)) 
    { 
    } 
}

Furthermore, you must start the transaction yourself (including the IsolationLevel if you want to avoid the default setting) and let the Entity Framework know that there is an existing transaction already started on the connection (see line 33 below).

Then you are free to execute database operations either directly on the SqlConnection itself, or on the DbContext. All such operations are executed within one transaction. You take responsibility for committing or rolling back the transaction and for calling Dispose() on it, as well as for closing and disposing the database connection. E.g.:

static void UsingExternalTransaction()
{
using (var conn = new SqlConnection("..."))
{
conn.Open(); using (var sqlTxn = conn.BeginTransaction(System.Data.IsolationLevel.Snapshot))
{
try
{
var sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.Transaction = sqlTxn;
sqlCommand.CommandText =
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'";
sqlCommand.ExecuteNonQuery(); using (var context =
new BloggingContext(conn, contextOwnsConnection: false))
{
context.Database.UseTransaction(sqlTxn); var query = context.Posts.Where(p => p.Blog.Rating >= );
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges();
} sqlTxn.Commit();
}
catch (Exception)
{
sqlTxn.Rollback();
}
}
}
}

EF Working with Transactions的更多相关文章

  1. Asp.net core 学习笔记 ( ef core transaction scope & change level )

    ef core 有 unit of work 的概念,当我们 save change 时会自动使用 transaction 确保更新的一致性. 隔离级别是默认的 read committed 不允许脏 ...

  2. DotNetCore跨平台~EFCore废弃了TransactionScope取而代之的Context.Database.BeginTransaction

    回到目录 TransactionScope是.net平台基于的分布式事务组件,它默认为本地事务,同时当系统有需要时可以自动提升为分布式事务,而对系统的前提是要开启MSDTC服务,必要时需要在数据库服务 ...

  3. EntityFramework Core进行读写分离最佳实践方式,了解一下(一)?

    前言 本来打算写ASP.NET Core MVC基础系列内容,看到有园友提出如何实现读写分离,这个问题提的好,大多数情况下,对于园友在评论中提出的问题,如果是值得深究或者大多数同行比较关注的问题我都会 ...

  4. 记unit of work与事务提交

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using- ...

  5. EntityFrameworkCore 开发实践问题及规范

    严重问题 客户端求值 如where条件包含的GetValueOrDefault()不能被翻译成sql语句 不规范代码段例子 public async Task<List<Person> ...

  6. EFCore 5 新特性 —— Savepoints

    EFCore 5 中的 Savepoints Intro EFCore 5中引入了一个新特性,叫做 Savepoints,主要是事务中使用,个人感觉有点类似于 Windows 上的系统还原点,如果事务 ...

  7. %E3%80%90%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E3%80%91

    "%3Cdiv%20class%3D%22htmledit_views%22%20id%3D%22content_views%22%3E%0A%20%20%20%20%20%20%20%20 ...

  8. 一次EF批量插入多表数据的性能优化经历

    距离上次的博客已经有15个多月了,感慨有些事情还是需要坚持,一旦停下来很有可能就会停很久或者从此再也不会坚持.但我个人一直还坚持认为属于技术狂热份子,且喜欢精益求精的那种.最近遇到两个和数据迁移相关的 ...

  9. EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)

    官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞.请大 ...

随机推荐

  1. 【.net】未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序解决办法

    #错误描述: 在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错: “未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序” # ...

  2. 金融量化分析【day112】:初识量化交易

    一.摘要 为什么需要量化交易? 量化交易是做什么? 量化交易的价值何在? 做量化交易需要什么? 聚宽是什么? 零基础如何快速入门量化交易? 自测与自学 二.量化交易比传统交易强多少? 它能让你的交易效 ...

  3. java matlab 混合编程 Failed to find the required library mclmcrrt9_2.dll on java.library.path.

    问题描述: Exception in thread "main" java.lang.UnsatisfiedLinkError: Failed to find the requir ...

  4. JDBC Template

    JDBC Template 1. Spring JDBC Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象用来简化JDBC的开发 步骤: 导入jar包 创建JDBCTemp ...

  5. 求复变函数的 Taylor 展式与 Laurent 展式[华中师范大学2010年复变函数复试试题]

    设 $$\bex f(z)=\frac{1}{(z-1)(z-2)}. \eex$$ (1) 求 $f(z)$ 在 $|z|<1$ 内的 Taylor 展式. (2) 求 $f(z)$ 在圆环 ...

  6. 在JS中如何判断所输入的是一个数、整数、正数、非数值?

    1.判断是否为一个数字: Number(num)不为 NaN,说明为数字 2. 判断一个数为正数: var num=prompt("请输入:"); if(Number(num)&g ...

  7. Concurrent下的线程安全集合

    1.ArrayBlockingQueue ArrayBlockingQueue是由数组支持的线程安全的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序.这是一个典型的“有界缓存区”,固定 ...

  8. Ansible-----条件判断与错误处理

    when 在ansible中,条件判断的关键词是when --- - hosts: all remote_user: root tasks: - debug: msg: "System re ...

  9. Python-Django基础

    django目录 -settings -urls -views ******强调:setting中'django.middleware.csrf.CsrfViewMiddleware'中间件先注释掉 ...

  10. javascript中字符串的方法

    字符串的方法 charAt();返回字符串指定索引的字符: concat();连接两个或多个字符串: indexOf();返回字符串中检索指定字符第一次出现的位置: lastIndexOf();返回字 ...