Orm 存储库的预期行为

Orm 存储库的预期行为,orm,domain-driven-design,unit-of-work,ddd-repositories,poeaa,Orm,Domain Driven Design,Unit Of Work,Ddd Repositories,Poeaa,我正在编写一个ORM,不确定存储库的预期行为,或者更准确地说,不确定存储库和工作单元之间的边界。 根据我的理解,存储库可能如下所示: interface IPersonRepository { public function find(Criteria criteria); public function add(Person person); public function delete(Person person); } 根据福勒(PoEAA,第322页): 存储库

我正在编写一个ORM,不确定存储库的预期行为,或者更准确地说,不确定存储库和工作单元之间的边界。 根据我的理解,存储库可能如下所示:

interface IPersonRepository
{
    public function find(Criteria criteria);
    public function add(Person person);
    public function delete(Person person);
}
根据福勒(PoEAA,第322页):

存储库在域和数据映射层之间进行中介,就像内存中的域对象集合一样。[…]对象可以添加到存储库中,也可以从存储库中删除,就像它们可以从简单的对象集合中删除一样

这意味着以下测试应该有效(假设我们已经有了一个姓Fowler的人):

这意味着,当映射到数据库时,即使没有在某处调用显式save()方法,Person模型也必须由存储库自动持久化,以便下一个查询返回正确的集合,而不是包含原始Person的

但是,这难道不是工作单元的角色吗?决定将哪个模型持久化到数据库,以及何时持久化

在上述实现中,存储库必须决定在接收另一个find()调用时保留先前检索到的人员,以便结果与修改一致。但是,如果没有发出其他find()调用,则该模型将根本不会被隐式持久化

在工作单元的上下文中,这并不是一个真正的问题,因为我们可以在开始时启动事务,并在需要时回滚对数据库的任何插入。 但是当单独使用时,这个存储库不会导致意外的、不可预测的行为吗

存储库在 域和数据映射层,代理 类似于内存中的域对象 收集可以添加[…]个对象 从存储库中删除,如所示 它们可以从一个简单的 对象

这并不意味着您不需要save方法。您仍然需要显式地将更改提交到存储

在某种程度上,您可以将工作单元视为转储所有事务处理代码的地方。工作单位的职责是:

  • 管理交易
  • 对数据库的插入、删除和更新进行排序
  • 防止重复更新。在工作单元对象的单一用法中,代码的不同部分可能会将同一发票对象标记为已更改,但工作单元类只会向数据库发出单个更新命令

    • 我想你想什么;我们询问的问题如下:


      存储库应将获取的对象保留在内存中,并且对该实体的所有后续调用都不应从持久性存储中检索,因此您的示例应该可以正常工作。

      谢谢Todd,但我的问题目前主要集中在存储库模式上。您的意思是我应该向存储库添加一个
      save(Person)
      函数吗?但是,如果在测试中,我对我的存储库使用内存策略,对生产数据库策略使用内存策略,该怎么办;我将从这两个函数中得到不同的结果,因为内存策略将向第二个find()调用返回不同的集合,即使这个人没有被save()d?我将编写测试,集中于执行单个读取/更新/验证的简单CRUD操作。您通常不希望使用基于内存的存储库的同一实例运行一系列测试。我总是为每个运行的测试方法创建一个新的内存存储库。我仍然认为,一个100%符合PoEAA描述的存储库即使在现实世界中不是不可能的,也是非常棘手的事情!谢谢你的评论。更新:我刚刚发现,像Hibernate这样的ORM确实可以通过在发出
      find()
      调用时自动刷新对数据库的更改来解决这个问题,以保证一致的读取。但是,这仍然必须在工作单元的上下文中执行,或者在需要时无法回滚更改;但在我的示例中,find()函数需要在数据库中执行搜索,这是另一回事。如果希望第二个find()返回最新结果,则必须首先刷新()对数据库的挂起更改。
      collection = repository.find(lastnameEqualsFowlerCriteria);
      person = collection[0];
      
      assertEquals(person.lastname, "Fowler");
      
      person.lastname = "Evans";
      newCollection = repository.find(lastnameEqualsFowlerCriteria);
      
      assertFalse(newCollection.contains(person));
      
      public interface IUnitOfWork {
        void MarkDirty(object entity);
        void MarkNew(object entity);
        void MarkDeleted(object entity);
        void Commit();
        void Rollback();
      }