.net core2.x

阅读: 评论:0

.net core2.x

.net core2.x

概要:在搭建框架,顺手说下写下,关于unitofwork,可能你理解了,可能你还不理解,可能与不可能不是重点,重点是感兴趣就看看吧。

1.工作单元(unitofowork)是什么(后面简写uow)?

  Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

  Unit of Work --Martin Fowler

  uow是这个老兄(马丁)提出的,上面是他说的话,这里要注意的就是分两个时间点,a)业务操作过程中,对操作的CUD操作的对象的状态进行跟踪操作; b) CUD操作完必经的一步骤当然是提交到数据库,uow保证业务提交使用同意上下文对象,从而保证了事务的一致性,假设提交失败直接回滚。

  简单说:uow可以说是一个开关,开:用于上下文的获取,供所有的仓储对象使用;关:提交操作,提交的过程包含事务控制(是否会滚)。

  所以他这一句话我们可以明确这几个东西:

  ①:一个对象用于存放 业务操作的对象(我们结合仓储使用就是仓储了) repository的临时存储对象;

  ②:同一业务操作的上下文必须保持一致(同一上下文对象)

  3  :维护当前业务的变更操作(微软自带输入法打不出来圆圈三,,,,)

  ④:事务控制

  依据这几点,所以我们可以和容易写出我们想要的代码,(临时先刨除 第三点 ,后面会有补充),先声明:这里未考虑多上下文的情况,因为我这边用不到,但是实现也比较简单,可以将涉及到的hashtable对象换成dictionary等,键为上下位对象类型或者名称。

public class UnitOfWork : IUnitOfWork{#region fields/// <summary>///     服务提供器,主要用于查找 框架配置对象,以及DbContextOptionBuilder对象/// </summary>private readonly IServiceProvider _provider;/// <summary>///     当前请求涉及的scope生命的仓储对象/// </summary>private Hashtable repositorys;private IDbContextTransaction _dbTransaction { get; set; }/// <summary>///     上下文对象,UOW内部初始化上下文对象,供当前scope内的操作使用,保证同一上下文/// </summary>public DbContext DbContext => GetDbContext();#endregion#region ctorpublic UnitOfWork(IServiceProvider provider){_provider = provider;}#endregion#region publicpublic IRepository<TEntity, TKey> Repository<TEntity, TKey>() where TEntity : class, IEntity<TKey>{if (repositorys == null)repositorys = new Hashtable();var entityType = typeof(TEntity);if (!repositorys.ContainsKey(entityType.Name)){var baseType = typeof(Repository<,>);var repositoryInstance = Activator.CreateInstance(baseType.MakeGenericType(entityType), DbContext);repositorys.Add(entityType.Name, repositoryInstance);}return (IRepository<TEntity, TKey>)repositorys[entityType.Name];}public void BeginTransaction(){//DbContext.Database.UseTransaction(_dbTransaction);//如果多上下文,我们可是在其他上下文直接使用 UserTransaction使用已存在的事务_dbTransaction = DbContext.Database.BeginTransaction();}public int Commit(){int result = 0;try{result = DbContext.SaveChanges();if (_dbTransaction != null)_dbTransaction.Commit();}catch (Exception ex){result = -1;CleanChanges(DbContext);_dbTransaction.Rollback();throw new Exception($"Commit 异常:{ex.InnerException}/r{ ex.Message}");}return result;}public async Task<int> CommitAsync(){int result = 0;try{result = await DbContext.SaveChangesAsync();if (_dbTransaction != null)_dbTransaction.Commit();}catch (Exception ex){result = -1;CleanChanges(DbContext);_dbTransaction.Rollback();throw new Exception($"Commit 异常:{ex.InnerException}/r{ ex.Message}");}return await Task.FromResult(result);}#endregion#region privateprivate DbContext GetDbContext(){var options = _provider.ESoftorOption();IDbContextOptionsBuilderCreator builderCreator = _provider.GetServices<IDbContextOptionsBuilderCreator>().FirstOrDefault(d => d.DatabaseType == options.ESoftorDbOption.DatabaseType);if (builderCreator == null)throw new Exception($"无法解析数据库类型为:{options.ESoftorDbOption.DatabaseType}的{typeof(IDbContextOptionsBuilderCreator).Name}实例");//DbContextOptionsBuildervar optionsBuilder = builderCreator.Create(options.ESoftorDbOption.ConnectString, null);//TODO null可以换成缓存中获取connection对象,以便性能的提升if (!(ActivatorUtilities.CreateInstance(_provider, options.ESoftorDbOption.DbContextType, optionsBuilder.Options) is DbContext dbContext))throw new Exception($"上下文对象 “{options.ESoftorDbOption.DbContextType.AssemblyQualifiedName}” 实例化失败,请确认配置文件已正确配置。 ");return dbContext;}/// <summary>///     操作失败,还原跟踪状态/// </summary>/// <param name="context"></param>private static void CleanChanges(DbContext context){var entries = context.ChangeTracker.Entries().ToArray();for (int i = 0; i < entries.Length; i++){entries[i].State = EntityState.Detached;}}#endregion#region overridepublic void Dispose(){_dbTransaction.Dispose();DbContext.Dispose();GC.SuppressFinalize(this);}#endregion}
View Code

  接口定义:

/// <summary>///     工作单元接口/// </summary>public interface IUnitOfWork : IDisposable{IRepository<TEntity, TKey> Repository<TEntity, TKey>() where TEntity : class, IEntity<TKey>;void BeginTransaction();int Commit();Task<int> CommitAsync();}
View Code

 

2.怎么用?

  就目前而言,博客园中可见到的大部分的 实现都是将uow注入到 repository,通过 uow获取上下文对象,然后在 service中只是直接注入所需的 repository对象,是的,这的确满足我们的开发需求了,也能正常运行。

public class TestService
{private readonly ITestRepository _testRepository;public TestService(ITestRepository testRepository){_testRepository = testRepository;}  //......其他方法实现
}    

  如果有多个仓储对象,依次如上面的方式注入即可。但是,这样做的话,当以后我们有表删除或者新增的时候,我们不得不维护这样的列表。这完全不符合OO设计原则;如果我们有新表的创建或者删除,改动就比较多了。

  如果你有细细观察的话,我们这里的 UOW实现稍有不同,也就涉及到当前请求的 仓储对象(repository),我们在这零时存储到了一个 hashable对象中,那么这时候我们在 service中使用uow和仓储的时候,就不用像上面那样,有多少个需要注册多少次,而只需要注入我们的一个uow对象即可。然后通过uow获取 仓储(repository)对象,因为我们零时将涉及到当前请求(事务)的 仓储已经存储到私有变量的 hashtable中,

public class TestService
{private readonly IUnitOfWork _uow;public TestService(IUnitOfWork uow){_uow = uow;}  //......其他方法实现
} 

  然后我们在使用仓储(repository)的时候,只需要如下方式使用即可:

  var userRepository = _uow.Repository<User,Guid>();

  var roleRepository = _uow.Repository<Role,Guid>();

  ...

  而在我们用到事务的地方,直接使用uow中的commit提交即可:

  _uow.BeginTransaction();

  var userRepository = _uow.Repository<User,Guid>();

  var roleRepository = _uow.Repository<Role,Guid>();

  ...//一些列其他操作,(CRUD)

  _uow.Commit();

  就像上面说到的,这样保证了当前业务操作涉及的 仓储对象(repository),会保证在 hashtable对象中,同时使用同一个上线问对象(DbContext),Commit提交的时候保证了事务(上下文)的一致性。而且如上面提到的,我们只需要在service层中注入一个uow即可,不论表如何变动,删除或者新增表,我们这里不会收到任何影响。比较理想的一种方式。

 

3.注意点?

  uow模式注意点,也就是uow的说明 即:

  1.由uow初始化上下文对象,也就是我们代码中的DbContext,;

  2.由uow提供事务的控制方法,以及控制事务回滚,保证最终一致性

  3.这里我们还使用了uow进行仓储对象的 获取。

  4.其他

  

4.补充:对象操作状态的控制?

  上面有说到,uow还需要对操作状态的控制?啥意思?简单说就是,一系列的 增、删、改的 命令操作 的状态控制,这里的实现,园子已经在很早之前就有比较完善的实现了:

  .html

  基本原理就是 类似我们定义的 hashtable对象,定义三个 Dictionary 变量,用于存储当前 业务操作涉及的 增、删、改、三种操作的 存储变量。

 

完。

 

转载于:.html

本文发布于:2024-01-27 17:54:37,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17063492771757.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:net
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23