原文: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 core 多租户框架整理

    一 saaskitAsp.Net Core multi-tenant application Sample using #SaaSKithttps://github.com/saaskit/saask ...

  2. ORACLE升级PSU&OJVM注意的问题及遇到问题解决思路

    [环境介绍] 系统环境:Solaris + Oracle 11R2 + OGG + 脚本定时任务统计信息收集 [背景描述] 基于集团的安全检查,需要对数据库版本进行漏洞扫描,漏洞扫描中存在RBDMS和 ...

  3. Regularity criteria for NSE 5: $u_3,\om_3$

    In [Zhang, Zujin. Serrin-type regularity criterion for the Navier-Stokes equations involving one vel ...

  4. 乘积型Sobolev不等式

    (Multiplicative Sobolev inequality). Let $\mu,\lambda$ and $\gamma$ be three parameters that satisfy ...

  5. 【hdu 5217】Brackets

    Description Miceren likes playing with brackets. There are N brackets on his desk forming a sequence ...

  6. jQuery.rotate.js(控制图片转动)

    jQuery.rotate.js笔记   1. jQuery.rotate.js是什么 一个开源的兼容多浏览器的jQuery插件用来对元素进行任意角度的旋转动画. 这个库开发的目的是为了旋转img的, ...

  7. Angular7_获取异步方法里面的数据

    1.回调函数 getName() { return '张三'; } getAsyncName() { setTimeout(() => { return 'async_张三'; }, ); } ...

  8. BIO 和 NIO

    一.阻塞(Block)和非阻塞(NonBlock) 阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候阻塞: 阻塞:往往需要等待缞冲区中的数据准备好过后才处理其他 ...

  9. rocketmq 4.2.0集群配置

    采用的是2m-2s-async模式 1.  修改每台机器的/etc/hosts  文件,增加如下内容 192.168.1.100 nameserver1192.168.1.102 nameserver ...

  10. storage和memory

    memory:使用的是值传递,默认使用的是memory,传递的是值 storage:引用传递,传过来的是指针,后面一定要加上internal,private pragma solidity ^; co ...