# [Unit Of Work](https://medium.com/@martinstm/unit-of-work-net-core-652f9b6cf894) 这个模式关注的是对象的变化。正如 Martin Fowler 所说,这个单元在事务上下文中保留了一个变化的对象列表。同时管理写操作,处理并发问题。我们可以把它看作是一个上下文、会话或对象,它在事务过程中跟踪所有数据模型上的变化。 ## 架构概述 ![UOW](../images/UOW0.png) 所以我们有接口、实现和两个服务与 UnitOfWork 的依赖。 ## 给我看一些代码 下面的代码块显示了一个简单的接口来实现这个模式的主要目的: ```csharp public interface IUnitOfWork { void BeginTransaction(); void SaveChanges(); bool Commit(); void Rollback(); } ``` 如你所想,这些名字的灵感来自于任何数据库的操作。 BeginTransaction 应该启动事务。如果你使用的是 SQL 数据库,你可以在这里定义隔离级别,例如。 此刻我们可以开始创建和更新一些对象,然后调用 SaveChanges 方法。这个方法的目标是在事务中保持这些变化在内存中的可用性。当我们在打开的事务中完成了所有的更改,如果一切都符合数据存储规则,我们可以 Commit,否则我们调用 Rollback 来丢弃所有这些更改,以防出现任何错误。 ## 一个简单的使用实例 ```csharp public void Update(Person person) { UnitOfWork.BeginTransaction(); try { PersonService.Update(person); PersonHistoryService.Create(person.Id, "Person updated!"); } catch (Exception e) { UnitOfWork.Rollback(); _logger.LogError(e.Message); } UnitOfWork.Commit(); } ``` 步骤: 1. 开启事务 2. 更新 "人员",并在历史表中创建一个新条目。 3. 每个服务都会调用 SaveChanges 4. 如果捕捉到异常,使用回滚丢弃更改,并记录一条消息。 5. 如果一切正常,提交事务并将这些更改写入存储系统中 这是一个基本案例,展示了如何使用 UnitOfWork 服务。重要的是要明白,当我们调用 SaveChanges 时,我们只是在事务范围内将这些对象保留在内存中。这些变化只是在我们提交事务时才被持久化在数据存储中。 这是一个我们做了多个更改的情况,我们必须保证所有的更改在同一时间被存储。然而,我们可能会有这样的情况:我们没有打开事务,我们只需要在最后调用 SaveChanges。 ## 一个更简单的使用例子 在接下来的代码块中,我们有来自服务的方法来创建一个历史记录。在存储库调用后,我们只需要保存这些变化。 ```csharp public void Create(int personId, string message) { PersonHistory history = new PersonHistory(personId, message); NoteRepository.Insert(history); UnitOfWork.SaveChanges(); } ``` 我们可以看到,这个方法调用了 SaveChanges,如果我们想在没有事务的情况下创建历史记录,那就足以存储数据。 ## 仓储模式重要性 考虑到前面的例子,我们知道我们必须在类的构造函数中配置所有使用的仓储(PersonRepository 和 NoteRepository)的依赖注入。如果工作单元知道如何给我们一个特定的存储库的实例,以保持代码的简单性,那就太好了。 ```csharp UnitOfWork.Repository().Insert(note); ``` 正如我们所看到的,它很容易使用,而且在我们的构造函数中不需要那么多的依赖。我们只需要有 IUnitOfWork 依赖。 为了得到这个行为,我们应该改变接口: ```csharp public interface IUnitOfWork { void BeginTransaction(); void SaveChanges(); bool Commit(); void Rollback(); IRepository Repository(); } ``` 正如我们所看到的,实现 仓储模式 是非常重要的。这个新方法只适用于我们定义了这种模式的情况。 工作单元保存一个字典,其中键是 TEntity 类型的名称,值是一个动态对象,它将是 TEntity 的存储库的实例。如果字典中已经有该类型的值,它将返回它。如果没有,它将创建一个新的实例并存储它。我们可以在下面的代码块中看到这个算法。 ```csharp private Dictionary _repositories; public IRepository Repository() { if (_repositories == null) _repositories = new Dictionary(); var type = typeof(TEntity).Name; if (_repositories.ContainsKey(type)) return (IRepository)_repositories[type]; var repositoryType = typeof(Repository<>); _repositories.Add(type, Activator.CreateInstance( repositoryType.MakeGenericType(typeof(TEntity)), this) ); return _repositories[type]; } ``` ## 结论 这是对 Unit Of Work 模式的概述以及一些使用和架构设计的例子。我假设我们使用一个存储系统来持久化数据。它可以是任何类型的存储,你只需要改变如何实现 IUnitOfWork 接口的方式。