ASP.NET MVC4+EF系列之七仓储中的事务实现 实现IUnitOfWork接口
很多了解EF的都知道。EF本身的SaveChange()方法是自带事务功能。就是在SaveChange()方法之前的对DbConext的操作都会被当成一个事务去处理。当是在一个框架系统中,SaveChange也许是满足不了需求的。所以就让IUnitOfWork的存在提供了必要条件。IUnitOfWork只是一个接口,为我们提供一个规范。至于具体实现各个ORM是不一样的。当时只要按照这个标准去做我们都是支持的。:)。
/***************************************************** * 作者:egojit * 日期:2012-7-13 * 描述:事务接口 * ***************************************************/ namespace EgojitFramework.Domain { /// <summary> /// 单元工作,为了管理事物 /// </summary> public interface IUnitOfWork { /// <summary> /// /// 返回一个Bool型用于标识单元工作是否被提交 /// </summary> bool Committed { get; } /// <summary> /// 提交单元工作 /// </summary> void Commit(); /// <summary> /// 回滚单元工作 /// </summary> void Rollback(); } }
大家可以看到这个借口很简单,一个属性用于判定事务是否已经被提交。另外两个方法就顾名思义,一个提交事务,一个回滚事务。
接下来不用说,我们关注他的继承类和事务是如何去实现的。大家打开我提供的源码可以看到它被RepositoryContextManager类继承。
#region IUnitOfWork 成员 /// <summary> /// 判断事务是否被提交 /// </summary> public bool Committed { get { return context.Committed; } } /// <summary> ///提交事务 /// </summary> public void Commit() { context.Commit(); } /// <summary> /// 回滚事务 /// </summary> public void Rollback() { context.Rollback(); } #endregion
从这段代码大家看不到任何东西,但是别急。这个我只是和大家分析一个实现过程。而上面的context其实是IRepositoryContext类型。大家打开这个接口很容易看到它也继承了IUnitOfWork这会大家忽然明白所有的实现在IRepositoryContext的实现类中。RepositoryContext类继承了IRepositoryContext接口,然后我们从代码中发现关于IUnitOfWork接口的方法欧式抽象的abstract的,那么它肯定被实现。不难理解其实这个RepositoryContext仓储环境还只是一般的,而非针对特殊的ORM去实现的。在此我们很容易想到我们这里的ORM工具是EF那么它的实现肯定在EntityFrameworkRepositoryContext类中,对了,我们猜测的没错。EntityFrameworkRepositoryContext:
public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
我们看到他继承了RepositoryContext这个类,那我们在回到这个类:
using System; using System.Collections.Generic; using EgojitFramework.Infrastructure; /***************************************************** * 作者:egojit * 日期:2012-7-13 * 描述:仓储上下文基础类 * ***************************************************/ namespace EgojitFramework.Domain.Repositories { /// <summary> ///仓储上下文基础类 /// </summary> public abstract class RepositoryContext : DisposableObject, IRepositoryContext { #region 私有字段 private readonly Guid id = Guid.NewGuid(); [ThreadStatic] private readonly Dictionary<Guid, object> newCollection = new Dictionary<Guid, object>(); [ThreadStatic] private readonly Dictionary<Guid, object> modifiedCollection = new Dictionary<Guid, object>(); [ThreadStatic] private readonly Dictionary<Guid, object> deletedCollection = new Dictionary<Guid, object>(); [ThreadStatic] private bool committed = true; #endregion
发现还有这样一段代码,他们就是用来放那些,删除,修改,添加的对象,用GUID作为Key,这个就是本地内存,首先将对象的改变都放在这三个集合中。可以看看
RepositoryContext类中对IRepositoryContext接口的实现这里我就贴其中的一个代码
/// <summary> /// 注册一个新的对象到仓储环境 /// </summary> /// <typeparam name="TAggregateRoot">仓储根类型.</typeparam> /// <param name="obj">被注册的对象的名字.</param> public virtual void RegisterNew<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot { if (obj.ID.Equals(Guid.Empty)) throw new ArgumentException("The ID of the object is empty.", "obj"); if (modifiedCollection.ContainsKey(obj.ID)) throw new InvalidOperationException("The object cannot be registered as a new object since it was marked as modified."); if (newCollection.ContainsKey(obj.ID)) throw new InvalidOperationException("The object has already been registered as a new object."); newCollection.Add(obj.ID, obj); committed = false; }
这样将他们放入字典中。并且 committed = false;再回到EntityFrameworkRepositoryContext类中我们看看事务的实现代码
/***************************************************** * 作者:egojit * 日期:2012-8-14 * 描述:角色服务 * ***************************************************/ using System; using System.Data.Entity; using System.Data.Entity.Validation; using EgojitFramework.Domain.Model; namespace EgojitFramework.Domain.Repositories { public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext { private readonly EgojitFrameworkContext ctx = new EgojitFrameworkContext(); private readonly object sync = new object(); public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj) { ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Deleted; Committed = false; } public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj) { ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified; Committed = false; } public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj) { ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Added; Committed = false; } public override void Commit() { if (!Committed) { lock (sync) { try { ctx.SaveChanges(); Committed = true; } catch (DbEntityValidationException e) { foreach (var eve in e.EntityValidationErrors) { Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State); foreach (var ve in eve.ValidationErrors) { Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage); } } throw; } } } } public override void Rollback() { Committed = false; }
至此我们了解了整个事务的实现过程。这样实现的事务是不是更加灵活。我们不需要频繁的去链接数据库,所有的操作都在本地内存。直到我们提交。
版权:本文属博客园和egojit所有,转载请标明出处