Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 存储库和工作单元模式-如何保存更改_C#_Repository Pattern_Unit Of Work - Fatal编程技术网

C# 存储库和工作单元模式-如何保存更改

C# 存储库和工作单元模式-如何保存更改,c#,repository-pattern,unit-of-work,C#,Repository Pattern,Unit Of Work,我一直在努力理解存储库和工作单元模式之间的关系,尽管这种问题被问了很多次。从本质上讲,我仍然不知道哪个部分将保存/提交数据更改—存储库还是工作单元 因为我看到的每个示例都与将这些与数据库/或映射器结合使用有关,所以让我们制作一个更有趣的示例-让我们将数据持久化到数据文件中的文件系统;根据模式,我应该能够做到这一点,因为数据的去向是不相关的 因此,对于一个基本实体: public class Account { public int Id { get; set; } public

我一直在努力理解存储库和工作单元模式之间的关系,尽管这种问题被问了很多次。从本质上讲,我仍然不知道哪个部分将保存/提交数据更改—存储库还是工作单元

因为我看到的每个示例都与将这些与数据库/或映射器结合使用有关,所以让我们制作一个更有趣的示例-让我们将数据持久化到数据文件中的文件系统;根据模式,我应该能够做到这一点,因为数据的去向是不相关的

因此,对于一个基本实体:

public class Account
{
    public int Id { get; set; }
    public string Name { get; set; }
}
我设想将使用以下接口:

public interface IAccountRepository
{
     Account Get(int id);
     void Add(Account account);
     void Update(Account account);
     void Remove(Account account);
}

public interface IUnitOfWork
{
    void Save();
}
我认为从使用角度来看,它应该是这样的:

IUnitOfWork unitOfWork = // Create concrete implementation here
IAccountRepository repository = // Create concrete implementation here

// Add a new account
Account account = new Account() { Name = "Test" };
repository.Add(account);

// Commit changes
unitOfWork.Save();
请记住,所有数据都将持久化到文件中,实际添加/更新/删除这些数据的逻辑在哪里

  • 它是否通过
    Add()
    Update()
    Remove()
    方法进入存储库?在我看来,将所有读/写文件的代码放在一个地方是合乎逻辑的,但是
    IUnitOfWork
    接口的意义是什么
  • 它是否在
    IUnitOfWork
    实现中,在这种情况下,哪个还将负责数据更改跟踪?对我来说,这意味着存储库可以读取文件,而工作单元必须写入文件,但逻辑现在分为两个位置

  • 事实上,我对这一点还很陌生,但没有比我更聪明的人发表过:

    正如您所期望的,CRUDs发生在存储库中的代码,但是当调用Account.Add(例如)时,所发生的只是将Account对象添加到稍后要添加的内容列表中(跟踪更改)

    调用unitOfWork.Save()时,允许存储库查看其已更改内容的列表或UoW已更改内容的列表(取决于您选择如何实现该模式)并采取适当的行动-因此,在您的情况下,可能会有一个
    List NewItemsToAdd
    字段,该字段根据对.add()的调用跟踪要添加的内容。当UoW表示可以保存时,存储库实际上可以将新项目作为文件持久化,如果成功,则清除要添加的新项目列表

    好的,UoW的重点是跨多个存储库管理保存(这些存储库是我们要提交的逻辑工作单元)

    我很喜欢你的问题。
    我在EntityFramework中使用了Uow/Repository模式,它显示了EF的实际作用(在最终调用SaveChanges之前,上下文如何跟踪更改)。要在示例中实现此设计模式,您需要编写大量代码来管理更改。

    存储库可以在没有工作单元的情况下工作,因此也可以使用Save方法

    public interface IRepository<T>
    {
         T Get(int id);
         void Add(T entity);
         void Update(T entity);
         void Remove(T entity);
         void Save();
    }
    
    公共接口IRepository
    {
    T Get(int-id);
    无效添加(T实体);
    无效更新(T实体);
    无效删除(T实体);
    作废保存();
    }
    
    当您有多个存储库(可能有不同的数据上下文)时,使用工作单元。它跟踪事务中的所有更改,直到调用Commit方法将所有更改持久化到数据库(在本例中为文件)

    因此,当您在存储库中调用Add/Update/Remove时,它只会更改实体的状态,将其标记为Added、Removed或Dirty。。。调用Commit时,工作单元将在存储库中循环并执行实际的持久性:

    • 如果存储库共享相同的数据上下文,则工作单元可以直接与数据上下文一起工作以获得更高的性能(在本例中是打开并写入文件)

    • 如果存储库具有不同的数据上下文(不同的数据库或文件),工作单元将在同一TransactionScope中调用每个存储库的Save方法


    • 呃,事情很棘手。想象一下这个场景:一个repo将一些东西保存在数据库中,另一个保存在文件系统中,第三个保存在云上。你是怎么做到的

      作为指导原则,UoW应该提交一些东西,但是在上面的场景中,提交只是一个幻觉,因为您有3个非常不同的东西要更新。输入最终一致性,这意味着所有事情最终都是一致的(与使用RDBMS的时间不同)

      在消息驱动的体系结构中,UoW被称为传奇。关键是每个saga位可以在不同的时间执行。只有当所有3个存储库都更新时,Saga才会完成

      您不会经常看到这种方法,因为大多数时候您将使用RDBMS,但现在NoSql非常常见,因此经典的事务性方法非常有限

      所以,如果您确定只使用一个rdbms,请使用UoW事务并将关联的连接传递给每个存储库。最后,UoW将调用commit


      如果您知道或预期您可能需要使用多个rdbms或不支持事务的存储,请尝试熟悉消息驱动体系结构和saga概念。

      如果您想自己使用文件系统,那么使用文件系统可能会使事情变得非常复杂

      仅在提交UoW时写入。

      您需要做的是让存储库将所有IO操作排队到UnitOfWork中。比如:

      public class UserFileRepository : IUserRepository
      {
          public UserFileRepository(IUnitOfWork unitOfWork)
          {
              _enquableUow = unitOfWork as IEnquableUnitOfWork;
              if (_enquableUow == null) throw new NotSupportedException("This repository only works with IEnquableUnitOfWork implementations.");
      
          }
      
          public void Add(User user)
          {
              _uow.Append(() => AppendToFile(user));
          }
      
          public void Uppate(User user)
          {
              _uow.Append(() => ReplaceInFile(user));
          }
      }
      
      通过这样做,您可以同时将所有更改写入文件

      使用数据库存储库不需要这样做的原因是事务支持内置在数据库中。因此,您可以告诉DB直接启动一个事务,然后使用它来伪造一个工作单元

      交易支持


      这将非常复杂,因为您必须能够回滚文件中的更改,并防止不同线程/事务在同时事务期间访问相同的文件。

      通常,存储库处理所有读取,工作单元处理所有读取