工作单元位于领域层。
 
ABP的数据库连接和事务处理:
1,仓储类
ASP.NET Boilerplate opens a database connection and begins a transaction when entering a repository method.
当一个仓储方法开始执行时,ABP打开一个数据库连接并启用一个事务。
当仓储方法结束时,事务会被自动提交,数据库连接也会自动释放。
If the repository method throws any exception, transaction is rolled back and the connection is disposed. 
一旦仓储方法抛出任何异常,事务就会回滚,连接也会被释放。
In this way, a repository method is atomic (a unit of work). 

一个仓储方法就是一个工作单元。

If a repository method calls another repository method (in general, if a unit of work method calls another unit of work method), both uses same connection & transaction. The first entering method manages connection & transaction, others use it.
假如仓储方法调用另一个仓储方法,它们使用的是同一个连接,同一个事务。第一个被调用到的仓储方法负责管理连接和事务,另一个仓储方法则单使用不管理。
 
2,应用服务类
publicclass PersonAppService : IPersonAppService
{
privatereadonly IPersonRepository _personRepository;
privatereadonly IStatisticsRepository _statisticsRepository; publicPersonAppService(IPersonRepository personRepository, IStatisticsRepository statisticsRepository)
{
_personRepository = personRepository;
_statisticsRepository = statisticsRepository;
} publicvoidCreatePerson(CreatePersonInput input)
{
var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
_personRepository.Insert(person);
_statisticsRepository.IncrementPeopleCount();
}
}

在应用层里的service类中,一个服务方法就是一个工作单元。

原理跟仓储方法是一模一样的。
 
3,工作单元(直接操作Unit of work)
一个做法是使用特性:
[UnitOfWork]
publicvoidCreatePerson(CreatePersonInput input)
{
var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
_personRepository.Insert(person);
_statisticsRepository.IncrementPeopleCount();
}

上面的CreatePerson方法使用了[UnitOfWork]特性标签。

Thus, CreatePerson methods becomes unit of work and manages database connection and transaction, both repositories use same unit of work. Note that no need to UnitOfWork attribute if this is an application service method. See 'unit of work method restrictions' section.
CreatePerson方法称为工作单元,它负责管理数据库连接和事务,_personRepository和_statisticsRepository共用同一个工作单元。
要注意的是,如果这是一个应用服务方法,则不需要加UnitOfWork特性标签了。后文将会提及UnitOfWork特性应该用在什么地方。
 
另一个做法是使用 IUnitOfWorkManager.Begin(...)方法:
publicclass MyService
{
privatereadonly IUnitOfWorkManager _unitOfWorkManager;
privatereadonly IPersonRepository _personRepository;
privatereadonly IStatisticsRepository _statisticsRepository; publicMyService(IUnitOfWorkManager unitOfWorkManager, IPersonRepository personRepository, IStatisticsRepository statisticsRepository)
{
_unitOfWorkManager = unitOfWorkManager;
_personRepository = personRepository;
_statisticsRepository = statisticsRepository;
} publicvoidCreatePerson(CreatePersonInput input)
{
var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress }; using (var unitOfWork = _unitOfWorkManager.Begin())
{
_personRepository.Insert(person);
_statisticsRepository.IncrementPeopleCount(); unitOfWork.Complete();
}
}
}

You can inject and use IUnitOfWorkManager as shown here. Thus, you can create more limited scope unit of works. In this approach, you should call Complete method manually. If you don't call, transaction is rolled back and changes are not saved. Begin method has overloads to set unit of work options.

It's better and shorter to use UnitOfWork attribute if you don't have a good reason.

在上面代码的Myservice构造函数中IUnitOfWorkManager会被注入。使用using关键字,可以在一个限定的代码域内使用工作单元。在代码域的最后必须以Complete方法结束。如果不调用这个方法,事务就会回滚。

如无很好的理由,最好还是使用UnitOfWork特性标签,而不是使用_unitOfWorkManager.Begin()
 
更多工作单元细节
 
禁用工作单元
[UnitOfWork(IsDisabled = true)]
publicvirtualvoidRemoveFriendship(RemoveFriendshipInput input)
{
_friendshipRepository.Delete(input.Id);
}

无事务的工作单元

[UnitOfWork(false)]
public GetTasksOutput GetTasks(GetTasksInput input)
{
var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);
returnnew GetTasksOutput
{
Tasks = Mapper.Map<List<TaskDto>>(tasks)
};
}

这是特殊情况下才使用的东西,可能是因为高并发,希望不要因为使用事务锁住了某些数据表和数据列。

 
一个工作单元调用另一个工作单元
If a unit of work method (a method declared with UnitOfWork attribute) calls another unit of work method, they share same connection and transaction. First method manages connection, others use it. This true for methods run in same Thread (or in same request for web applications). Actually, when a unit of work scope begins, all codes executing in same thread shares same connection and transaction until the unit of work scope ends. This is true both for UnitOfWork attribute and UnitOfWorkScope class. If you create a seperated Thread/Task, it uses own unit of work.
同上面仓储方法里的描述,会共用同一个连接和事务。但是如果两个工作单元方法使用不同的线程,则不会共用。
 
自动保存
[UnitOfWork]
publicvoidUpdateName(UpdateNameInput input)
{
var person = _personRepository.Get(input.PersonId);
person.Name = input.NewName;
}
O/RM framework keep track of all changes of entities in a unit of work and reflects changes to the database.

如上面代码,我们不需要在代码里写_personRepository.Update方法,因为ORM框架会自动追踪变化并反映到数据库中。

 
IRepository.GetAll() 方法
[UnitOfWork]
public SearchPeopleOutput SearchPeople(SearchPeopleInput input)
{
//Get IQueryable<Person>var query = _personRepository.GetAll(); //Add some filters if selectedif (!string.IsNullOrEmpty(input.SearchedName))
{
query = query.Where(person => person.Name.StartsWith(input.SearchedName));
} if (input.IsActive.HasValue)
{
query = query.Where(person => person.IsActive == input.IsActive.Value);
} //Get paged result listvar people = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList(); returnnew SearchPeopleOutput { People = Mapper.Map<List<PersonDto>>(people) };
}
When you call GetAll() out of a repository method, there must be an open database connection since it returns IQueryable. This is needed because of deferred execution of IQueryable. It does not perform database query unless you call ToList() method or use the IQueryable in a foreach loop (or somehow access to queried items). So, when you call ToList() method, database connection must be alive.

在仓储方法、应用服务方法外面,如果使用到IRepository.GetAll()之类涉及到数据库读写的方法,必须加上UnitOfWork特性标签。

 
工作单元特性标签的限制
  • All public or public virtual methods for classes those are used over interface (Like an application service used over service interface).
  • All public virtual methods for self injected classes (Like MVC Controllers and Web API Controllers).
  • All protected virtual methods.
UnitOfWork特性标签可以用在上面列举的方法上。
建议把方法都写成virtual的。
UnitOfWork特性不能用于private的方法,因为
ASP.NET Boilerplate uses dynamic proxying for that and private methods can not be seen by derived classes. UnitOfWork attribute (and any proxying) does not work if you don't use dependency injection and instantiate the class yourself.
 
选项
publicclass SimpleTaskSystemCoreModule : AbpModule
{
publicoverridevoidPreInitialize()
{
Configuration.UnitOfWork.IsolationLevel = IsolationLevel.ReadCommitted;
Configuration.UnitOfWork.Timeout = TimeSpan.FromMinutes(30);
} //...other module methods
}

SaveChanges

sometimes, you may want to save changes to database in middle of a unit of work operation. In this case, you can inject IUnitOfWorkManager and call IUnitOfWorkManager.Current.SaveChanges() method. An example usage may be saving changes to get Id of a new inserted Entity in EntityFramework. Note that: if current unit of work is transactional, all changes in the transaction are rolled back if an exception occurs, even saved changes.
 
有时候我们想在工作单元还没结束时就保存变化,那么这时就要使用IUnitOfWorkManager.Current.SaveChanges() 方法。
但是要注意的是,即便执行了SaveChanges,最后若有异常抛出,事务发生回滚,SaveChanges也会回滚。
 
事件
三种事件:Completed,Failed ,Disposed
publicvoidCreateTask(CreateTaskInput input)
{
var task = new Task { Description = input.Description }; if (input.AssignedPersonId.HasValue)
{
task.AssignedPersonId = input.AssignedPersonId.Value; _unitOfWorkManager.Current.Completed += (sender, args) => { /* TODO: Send email to assigned person */ };
} _taskRepository.Insert(task);
}
 
 

ABP的工作单元的更多相关文章

  1. ABP框架 - 工作单元

    文档目录 本节内容: 简介 在ABP中管理连接和事务 约定的工作单元 UnitOfWork 特性 IUnitOfWorkManager 工作单元详情 禁用工作单元 非事务性工作单元 工作单元方法调用另 ...

  2. Abp之工作单元与事务

    环境:Abp1.2 疑问:没有调用工作单元的SaveChanges方法引起的事务提交时机的问题. 例如:有一个应用服务代码如下: public void CreatePhrase(PhraseCrea ...

  3. 【ABP】工作单元——不进行事物独立执行功能

    1.注入 private readonly IUnitOfWorkManager unitOfWorkManager; 2.构造 3.开启新事物 using (var unitOfWork = uni ...

  4. ABP官方文档翻译 3.6 工作单元

    工作单元 介绍 ABP中的连接和事务管理 传统的工作单元方法 控制工作单元 UnitOfWork特性 IUnitOfWorkManager 工作单元详情 禁用工作单元 无事务工作单元 一个工作单元方法 ...

  5. EntityFrameworkCore之工作单元的封装

    1. 简介 2. DbContext 生命周期和使用规范 2.1. 生命周期 2.2. 使用规范 2.3. 避免 DbContext 线程处理问题 3. 封装-工作单元 3.1. 分析 3.2. 设计 ...

  6. ABP(现代ASP.NET样板开发框架)系列之12、ABP领域层——工作单元(Unit Of work)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ABP是“ASP.NET Boilerplate Pr ...

  7. ABP理论学习之工作单元(Unit of Work)

    返回总目录 本篇目录 公共连接和事务管理方法 ABP中的连接和事务管理 仓储类 应用服务 工作单元 工作单元详解 关闭工作单元 非事务的工作单元 工作单元方法调用其它 工作单元作用域 自动保存 IRe ...

  8. 解析ABP框架中的事务处理和工作单元,ABP事务处理

    通用连接和事务管理方法连接和事务管理是使用数据库的应用程序最重要的概念之一.当你开启一个数据库连接,什么时候开始事务,如何释放连接...诸如此类的. 正如大家都知道的,.Net使用连接池(connec ...

  9. 基于DDD的.NET开发框架 - ABP工作单元(Unit of Work)

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

随机推荐

  1. LeetCode "Design Tic-Tac-Toe"

    We don't have to keep a complete chess board.. just counters! class TicTacToe { vector<int> cn ...

  2. Django常用命令及参数配置(Django 1.8.6)

    常用命令 #新建Django项目 django-admin startproject mysite(项目名) #新建一个APP cd mysite python manager.py startapp ...

  3. linux 分区重新格式化

    看分区挂载blkidcat /etc/fstab 先看已挂载的分区文件系统df -Th 再看所属用户与组 ll -h 看哪些进程占用分区 ps -ef|grep /backupfuser -m -v ...

  4. Velocity $ 和$! 区别

    输出指令 ${}过滤输出 输出表达式的计算结果,并进行过滤,比如:过滤变量中的HTML标签. 格式: ${expression} 示例: ${user.name} 注:HTTL缺省开启了EscapeX ...

  5. MyBatis无法根据中文条件查询出结果

    情况是这样的 , 以英文做参数可以查询到结果 , 以中文做参数则查询不到结果 在mysql workbench中执行sql , 可以查询到结果. 这是mybatis中没有指定utf-8的缘故导致的. ...

  6. gc之四--Minor GC、Major GC和Full GC之间的区别

    针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种: Partial GC:并不收集整个GC堆的模式 Young GC:只收集young gen的GC Old GC:只收集old ge ...

  7. 谈谈Java利用原始HttpURLConnection发送POST数据

    这篇文章主要给大家介绍java利用原始httpUrlConnection发送post数据,设计到httpUrlConnection类的相关知识,感兴趣的朋友跟着小编一起学习吧 URLConnectio ...

  8. mybatis处理一对一查询

    有班级表,老师表,要求给定班级id查出班级信息和班级对应的老师信息 1.使用嵌套结果方式 sql语句: <select id="findClasses" parameterT ...

  9. 几篇关于VisualStudio的调试工具文章

    现代的软件变得日益复杂,强大的调试功能也变得日益重要起来.在VisualStudio的最近几个版本中,在调试工具方面也是增强了不少的,本文转录了几个微软官方介绍的一些新增的调试功能的文章,如果能很好的 ...

  10. display:inline-block

    /* inline为行内元素不自动换行,不占用文档流,也就是说你在这个后面写一个元素这个元素会并排显示.block为块元素,单独占一行文档,并可以给这个块元素添加宽高背景颜色.而inline-bloc ...