16

Abp 源码分析(4):Unit of work

 4 years ago
source link: http://blog.tubumu.com/2020/01/09/abp-analysis-04/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Abp 源码分析(4):Unit of work

2020-01-092020-01-10Abp

工作单元是”对象-关系”行为的一种模式。维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决。——《企业应用架构模式》

1、工作单元的作用

工作单元只是将所有修改状态保存下来,在适当的时候在同一数据库连接和事务处理上下文中一次性将对象的变更提交到数据中。额外的优点是既减少了数据库调用次数,又避免数据库长事务。

注意:同一个工作单元一般不要跨线程使用。

2、工作单元和仓储(Repository)模式

工作单元常与仓储(Repository)模式一起使用。因为多个 Repository 可能做出多处更改,如果在 Repository 中调用 DbContext.SaveChangesDbContext.SaveChangesAsync(如果使用 Entity Framework 的话),则产生了多个相互隔离开的事务。

备注:实际上 Entity Framewok 也实现了仓储模式(DbSet)和工作单元模式(DbContext)。

3、工作单元和依赖注入(拦截器)

直接使用工作单元也是可以的。配合依赖注入和拦截器能将工作单元的创建和完成提交的工作自动化,也就是说避免了手工创建工作单元和手工调用 Complete/Commit 。这种自动化使得应对复杂业务逻辑时不用过于关注业务无关的事务安全问题。

二、基础设施

1、UnitOfWork 模块

Abp 的工作单元在 Volo.Abp.Uow 模块中实现。

1
2
3
4
5
6
7
8
9
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\AbpUnitOfWorkModule.cs
public class AbpUnitOfWorkModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
// 针对所有注册入依赖注入容器的服务,都将执行一次 UnitOfWorkInterceptorRegistrar.RegisterIfNeeded 方法。
context.Services.OnRegistred(UnitOfWorkInterceptorRegistrar.RegisterIfNeeded);
}
}

把 UntiOfWork 类(见下文)在依赖容器注册服务时,会为之添加拦截器 UnitOfWorkInterceptor,从而导致为实现类创建代理类(当然,就算不是 UnitOfwork 类但有其他拦截器,也会为实现类创建代理类)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\UnitOfWorkInterceptorRegistrar.cs
public static class UnitOfWorkInterceptorRegistrar
{
public static void RegisterIfNeeded(IOnServiceRegistredContext context)
{
// 如果实现类是 UnitOfWork 类型。
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\UnitOfWorkHelper.cs
if (UnitOfWorkHelper.IsUnitOfWorkType(context.ImplementationType.GetTypeInfo()))
{
// 添加拦截器,将导致为实现类创建代理类。
context.Interceptors.TryAdd<UnitOfWorkInterceptor>();
}
}
}

2、UnitOfWork 类

如果类或类的任意方法标注了 UnitOfWorkAttribute 或类实现了 IUnitOfWorkEnabled 接口,称之为 UntiOfWork 类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\UnitOfWorkHelper.cs
public static bool IsUnitOfWorkType(TypeInfo implementationType)
{
//Explicitly defined UnitOfWorkAttribute
if (HasUnitOfWorkAttribute(implementationType) || AnyMethodHasUnitOfWorkAttribute(implementationType))
{
return true;
}

//Conventional classes
if (typeof(IUnitOfWorkEnabled).GetTypeInfo().IsAssignableFrom(implementationType))
{
return true;
}

return false;
}

3、UnitOfWork 方法

什么是 UnitOfwork 方法?首先,UnitOfwork 方法一定是 UnitOfwork 类中的方法,而 UnitOfWork 类中的方法不一定是 UnitOfwork 方法。如果方法特别标注了 UnitOfWorkAttribute 则根据 UnitOfWorkAttribute 的 IsDisabled 属性判断;否则如果类型标记了 UnitOfWorkAttribute 则根据 UnitOfWorkAttribute 的 IsDisabled 属性判断;如果方法和类都没有标注 UnitOfWorkAttribute,则判断类型是否实现了 IUnitOfWorkEnabled 接口。

备注:在类型和方法都标记了 UnitOfWorkAttribute 情况下,方法的 UnitOfWorkAttribute 优先级高一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\UnitOfWorkHelper.cs
public static bool IsUnitOfWorkMethod([NotNull] MethodInfo methodInfo, [CanBeNull] out UnitOfWorkAttribute unitOfWorkAttribute)
{
Check.NotNull(methodInfo, nameof(methodInfo));

//Method declaration
var attrs = methodInfo.GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();
if (attrs.Any())
{
unitOfWorkAttribute = attrs.First();
return !unitOfWorkAttribute.IsDisabled;
}

if (methodInfo.DeclaringType != null)
{
//Class declaration
attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();
if (attrs.Any())
{
unitOfWorkAttribute = attrs.First();
return !unitOfWorkAttribute.IsDisabled;
}

//Conventional classes
if (typeof(IUnitOfWorkEnabled).GetTypeInfo().IsAssignableFrom(methodInfo.DeclaringType))
{
unitOfWorkAttribute = null;
return true;
}
}

unitOfWorkAttribute = null;
return false;
}

如果方法是 UnitOfWork 方法,则应用 UnitOfWork。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\UnitOfWorkInterceptor.cs
// 同步拦截(也有异步拦截)
public override void Intercept(IAbpMethodInvocation invocation)
{
// 如果不是 UnitOfWork 方法。
// File: abp\framework\src\Volo.Abp.Uow\Volo\Abp\Uow\UnitOfWorkHelper.cs
if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.Method, out var unitOfWorkAttribute))
{
invocation.Proceed();
return;
}

// 用工作单元的开启和完成,把方法真正的执行"包"起来。
using (var uow = _unitOfWorkManager.Begin(CreateOptions(invocation, unitOfWorkAttribute)))
{
invocation.Proceed();
uow.Complete();
}
}

三、UnitOfWork 的实现

MyZony[Abp vNext 源码分析] - 4. 工作单元 一文中,对 UnitOfWorkManagerUnitOfWork/ChildUnitOfWork 等类及其他基础设施已经做了足够的分析,详见该文。

https://uk.wikipedia.org/wiki/Unit_Of_Work
https://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work
https://darkcraft.gitbooks.io/abpdocument2chinese/content/Abp/3.4ABP%E9%A2%86%E5%9F%9F%E5%B1%82-%E5%B7%A5%E4%BD%9C%E5%8D%95%E5%85%83.html
https://www.jianshu.com/p/08d407669740
https://www.cnblogs.com/myzony/p/11112288.html
https://www.cnblogs.com/huaizuo/p/4838680.html
https://ithelp.ithome.com.tw/articles/10157700
https://github.com/Arch/UnitOfWork
https://stackoverflow.com/questions/36691532/dbcontext-savechanges-method-in-unitofwork-or-in-repository-which-is-better
https://www.cnblogs.com/wwh999/p/5458038.html


Recommend

  • 100
    • Github github.com 6 years ago
    • Cache

    GitHub - abpframework/abp: ABP vNext

    README.md ABP

  • 69
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    把ABP框架部署到Docker中

  • 28
    • dockone.io 5 years ago
    • Cache

    用ABP入门DDD

    前言 ABP框架 一直以来都是用DDD(领域驱动设计)作为宣传点之一。但是用过ABP的人都知道,ABP并不是一个严格遵循DDD的开发框架,又或者说,它并没有完整实现DDD的所有概念。

  • 10
    • www.cnblogs.com 4 years ago
    • Cache

    ABP开发框架的技术点分析(1)

    ABP开发框架的技术点分析(1) - 伍华聪 - 博客园ABP是ASP.NET Boilerplate的简称,ABP是一个开源且文档友好的应用程序框架。ABP不仅仅是一个框架,它还提供了一个最徍实践的基于...

  • 26
    • blog.tubumu.com 4 years ago
    • Cache

    Abp 源码分析(3):DI 和 Autofac

    Abp 的 DI 容器是基于 Microsoft 的依赖注入扩展库(Microsoft.Extensions.DependencyInjection nuget包)开发的。因此,它的文档在 A...

  • 19
    • blog.tubumu.com 4 years ago
    • Cache

    Abp 源码分析(2):模块

    Abp 本身是一个包含许多 nuget 包的模块化框架。它还提供了一个完整的基础架构来开发你自己的具有实体、服务、数据库集成、AP、UI 组件等等功能的应用程序模块。每个模块都应该定义一个模块类。模块类指实现了 IAbpModul...

  • 12
    • blog.tubumu.com 4 years ago
    • Cache

    Abp 源码分析(1):启动

    Abp 是一个开源应用程序框架,专注于基于 ASP.NET Core 的 Web 应用程序开发,但也支持开发其他类型的应用程序。本文先分析相关的几个类型,再分析 Abp 的启动流程。 二、AbpApplication这里的 Applic...

  • 17
    • www.cnblogs.com 4 years ago
    • Cache

    我和ABP vNext 的故事

    我和ABP vNext 的故事 Abp VNext是Abp的.NET Core 版本,但它不仅仅只是代码重写了...

  • 6

    ABP vNext 使用 Volo.Abp.Sms 包和 Volo.Abp.Emailing 包将短信和电子邮件作为基础设施进行了抽象,开发人员仅需要在使用的时候注入 ISmsSender 或 IEmailSender 即可实现短信发送和邮件发送。 二、源码分...

  • 13

    If you write code, write tests. – The Way of Testivus 目录 Table of Contents 背景 单元测试的重要性无需多言,但...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK