entity framework6异步操作和TranscationScope
我在stackoverflow上搜索但找不到类似的问题,请指出我是否已经有一个问题。
我试图用同步和异步操作实现一个通用的可重用存储库,但是我对entity framework和工作单元的了解很少,我很难找到实现它的正确方法。
我在SaveAndCommit操作中添加了一些变体,但不知道使用事务和异步执行此操作的最佳方法是什么。
– – 编辑 – –
根据我的理解,当执行多个操作时应该使用事务,但出于理解的目的,我将它用于一个操作。 (如果我错了,请纠正我)
这是我到目前为止所做的
public class Service : IService where TEntity : Entity { #region Constructor and Properties UnitOfWork _unitOfWork { get { return UnitOfWork.UnitOfWorkPerHttpRequest; } } protected DbSet Entities { get { return _unitOfWork.Set(); } } #endregion Constructor and Properties #region Operations public virtual IQueryable QueryableEntities() { return Entities; } public virtual async Task<IList> WhereAsync(Expression<Func> predicate) { return await Entities.Where(predicate).ToListAsync(); } public virtual IList Where(Expression<Func> predicate) { return Entities.Where(predicate).ToList(); } public virtual async Task FirstOrDefaultAsync(Expression<Func> predicate) { return await Entities.FirstOrDefaultAsync(predicate); } public virtual TEntity FirstOrDefault(Expression<Func> predicate) { return Entities.FirstOrDefault(predicate); } public virtual async Task GetByIdAsync(int id) { return await Entities.FindAsync(id); } public virtual TEntity GetById(int id) { return Entities.Find(id); } // Method to the change the EntityState public virtual void Save(TEntity entity) { if (entity.Id == 0) { Entities.Add(entity); } else { _unitOfWork.Entry(entity).State = EntityState.Modified; } } #region Need clarification here // Uses transaction scope to commit the entity and dispose automatically // call rollback but this is not async and don't have any async // functions (Or I could not find) public virtual void SaveAndCommit(TEntity entity) { using (var transaction = _unitOfWork.BeginTransaction()) { try { Save(entity); transaction.Commit(); } catch (DbEntityValidationException e) { } } } // This is asynchronous but don't uses transaction public virtual async Task SaveAndCommitAsync(TEntity entity) { try { Save(entity); await _unitOfWork.SaveChangesAsync(); } catch (DbEntityValidationException e) { } } // Tried to mix async and transaction but don't know if it will actually // work or correct way of doing this public virtual async Task SaveAndCommitWithTransactionAsync(TEntity entity) { using (var transaction = _unitOfWork.BeginTransaction()) { try { Save(entity); await _unitOfWork.SaveChangesAsync(); } catch (DbEntityValidationException e) { transaction.Rollback(); } } } #endregion Need clarification here public virtual async Task DeleteAsync(TEntity entity) { if (entity == null) return; Entities.Remove(entity); await _unitOfWork.SaveChangesAsync(); } //All similar methods for delete as for Save public virtual async Task CountAsync(Expression<Func> predicate = null) { if (predicate != null) { return await Entities.CountAsync(predicate); } return await Entities.CountAsync(); } #endregion Operations }
请指导我并建议实现这一目标的最佳方法。
现在看来,使用异步调用实现事务范围的正确方法是
public virtual async Task SaveAndCommitWithTransactionAsync(TEntity entity) { using (var transaction = _unitOfWork.BeginTransaction()) { Save(entity); await _unitOfWork.SaveChangesAsync(); // Still no changes made to database transaction.Commit(); //Rollback will automatically be called by using in dispose method } }
参考MSDN参考
博客有更清晰的描述
visualstudiomagazine.com 对于:当您调用SaveChanges时,在调用Transaction对象的Commit方法之前,您的所有更改都不会生效
编辑:
为了使事务范围与async-await
一起工作,从.NET 4.5.1开始,您可以将TransactionScopeAsyncFlowOption.Enabled
标志传递给其构造函数:
using (var scope = new TransactionScope(... , TransactionScopeAsyncFlowOption.Enabled))
这可以确保事务范围与continuation表现良好。 有关更多信息,请参阅获取TransactionScope以使用async / await 。
请注意,从.NET 4.5.1开始,此function可用。
编辑2:
好的,在@Jcl评论BeingTransaction
,我搜索并找到了这个答案 :
随着EF6的推出, Microsoft建议使用新的API方法:
Database.BeginTransaction()
和Database.UseTransaction()
。 System.Transactions.TransactionScope只是编写事务代码的旧样式。但
Database.BeginTransaction()
仅用于与数据库相关的操作事务 ,而System.Transactions.TransactionScope
使得可能的“普通C#代码”也是事务性的 。
TransactionScope
的新异步function的限制:
考虑到限制,似乎启动EF6及更高版本的新方法是使用Database.BeginTransaction()
而不是TransactionScope
。
总结:
这是编写异步事务作用域db调用的正确方法:
public virtual async Task SaveAndCommitWithTransactionAsync(TEntity entity) { using (var transaction = _unitOfWork.BeginTransaction()) { try { Save(entity); await _unitOfWork.SaveChangesAsync(); transaction.Commit(); } catch (DbEntityValidationException e) { } } }
请注意,如果您的作用域包含在using
语句中,则不应调用transaction.RollBack()
,因为如果提交失败,则会进行回滚。
一个相关问题: Entity Framework 6事务回滚
这篇相关文章为新API提供了更多信息
边注:
这段代码:
public virtual void SaveAndCommitAsync(TEntity entity) { try { Save(entity); _unitOfWork.SaveChangesAsync(); } catch (DbEntityValidationException e) { } }
不做你认为它正在做的事情。 当您执行异步方法时, 通常应使用await
关键字异步等待它。 这个方法:
- 使用
void
作为其返回类型。 如果这是一个异步API,则它至少需要async Task
。async void
方法仅适用于事件处理程序 ,这里显然不是这种情况 -
最终用户可能正在等待这种方法,它应该变成:
public virtual Task SaveAndCommitAsync(TEntity entity) { try { Save(entity); return _unitOfWork.SaveChangesAsync(); } catch (DbEntityValidationException e) { } }
如果要包含事务范围 ,则必须等待此方法:
public virtual async Task SaveAndCommitAsync(TEntity entity) { try { Save(entity); await _unitOfWork.SaveChangesAsync(); } catch (DbEntityValidationException e) { } }
其余的异步方法也是如此。 一旦有交易,请确保等待该方法。
此外,不要吞下这样的例外,对它们做一些有用的事情,或者根本不抓住。
上述就是C#学习教程:entity framework6异步操作和TranscationScope分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/998712.html