将存储库模式与文档数据库一起使用是否有意义?

发布于 2024-12-05 20:06:25 字数 281 浏览 0 评论 0原文

我目前正在尝试 MongoDB。我正在从 NHibernate/SQL 思维方式转变,因此最初我实现了用于数据访问的存储库模式

在我开始使用嵌套文档之前,这一切看起来都很好。现在开始看起来有点不匹配。然而,我对存储库很满意,并且喜欢它们提供的抽象、关注点分离和可测试性。

人们是否成功地将存储库模式与文档数据库结合使用?如果没有,您使用什么数据访问方法?抽象/SoC 怎么样?

I'm currently experimenting with MongoDB. I'm moving from a NHibernate/SQL mindset, and so initially I implemented a repository pattern for data access.

This was all looking fine until I started using nested documents. Now it's starting to seem like there's a bit of a mismatch. However, I'm comfortable with repositories, and like the abstraction, separation of concerns, and testability they provide.

Are people successfully using the repository pattern with document databases? If not, what data access methodology to you use? What about abstraction/SoC?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

被你宠の有点坏 2024-12-12 20:06:26

这是一个有趣的问题。在使用 MongoDB 时,我选择不使用存储库。这是主要的,因为文档数据库被用作读取存储(因此简化了存储在那里的数据)。

我想您必须重新考虑存储库是什么以及您从额外的抽象层中获得的优势。一个好的设计将尽可能具有最少的层数。

因此,存储库为您提供了一些持久性无知以及在公共数据上下文上使用工作单元的能力。它还可以提高您独立测试数据查询的能力(因为这些查询通常被抽象为可查询或规范)。

此外,一些文档数据库已经提供了存储库模式(RavenDB 等),因此不需要再有另一层。

因此,在我看来,使用存储库并不在于您的数据是否存储为关系表还是文档,而更多在于您从抽象中获得什么。

It's an interesting question. In my usage of MongoDB, I chose to not have a repository. This was primary because the document database was used as a read store (therefore simplifying the data that was stored there).

I guess you have to strip the consideration back to what a repository is and what advantages you get from the extra layer of abstraction. A good design will have the least number of layers possible.

A repository therefore gives you some persistence ignorance and the ability to use unit of work over a common context of data. It also can increase your ability to test queries against the data in isolation (because these are usually abstracted as queryables or specifications).

Also, some document databases already provide a repository pattern (RavenDB etc), so there is no need to have yet another layer.

So, it seems to me that using a repository is not so much about whether your data is stored as a relational table or a document, but more about what you gain from the abstraction.

为人所爱 2024-12-12 20:06:26

I don't know if this will help you but I was listening to a pod-cast a while back with Ayende Rahien talking about RavenDB. He was suggesting that a document actually maps fairly well to an aggregate in the DDD philosophy. If you're using nested documents to represent an aggregate and running into design issues perhaps nesting is not the best way to go?

我为君王 2024-12-12 20:06:26

思考“我是否应该使用 X”并不像专注于“我应该使用什么”那么有效?

存储库模式的替代方案是什么,权衡是什么,它们与您的领域和实现有何关系?

存储库非常适合在通用存储(例如 SQL)上强制执行一组预定义的模式。对于文档存储,我的印象是文档模式将比您通常在基于 SQL 的存储中看到的更大程度地确定访问模式。在这种情况下实现存储库可能会导致非常泄漏的抽象,其中底层文档结构的更改会对相关业务代码产生 1:1 的影响。在这种情况下,存储库提供的价值非常小。对我来说,文档存储很自然地适合工作单元 (UoW) 范例,其中工作单元是文档(或 doc+嵌套子文档,或文档集)。

正如您所提到的,存储库模式的另一个优点是对存储机制的抽象。代价通常是无法访问 Mongo 的低级实现特定功能。这对你来说值得权衡吗? NHibernate 与 SQL 紧密耦合,因此对 RDBMS 的所有重要功能具有丰富的功能抽象。我不知道 Mongo 有任何类似的框架,所以你确实会大大提高抽象级别。

您需要支持多个并发数据存储吗?例如,您是否会通过相同的数据层抽象将某些类型的数据写入 SQL,将其他类型的数据写入 Mongo?如果是这样,那么存储库是一个不错的选择。

如果您可以提供有关您的领域和实施的更多详细信息,那么我们可以深入了解您可能需要考虑的具体权衡

Thinking about "Should I use X or not" is not as productive as focusing on "What should I use"?

What are the alternatives to the repository pattern, what are the tradeoffs, and how do they relate to your domain and implementation?

Repositories are good for enforcing a predefined set of patterns over a general-purpose store (such as SQL). For a document store, my impression is that the document schema will determine the access patterns to a greater extend than you would typically see in a SQL based store. Implementing a repository in this case may lead to very leaky abstractions, where changes to the underlying document structure have a 1:1 impact on the relevant business code. In that case the repository provides very little value. To me document stores naturally lend themselves well to Unit-of-Work (UoW) paradigms where the unit of work is a document (or doc+nested subdocs, or sets of documents).

Another strength of the repository pattern is, as you mentioned, abstraction over the storage mechanism. The tradeoff is usually loss of access to low-level implementation-specific features of Mongo. Is that a worthwhile tradeoff for you? NHibernate is very tightly coupled to SQL, and hence has richly functional abstractions over all the important features of a RDBMS. I'm not aware of any similar framework for Mongo so you would really be raising the level of abstraction quite a bit.

Do you need to support multiple concurrent data stores? For example, will you be writing some types of data to SQL and others to Mongo, through the same data layer abstraction? If so then a repository is a good option.

If you can provide some more details of your domain and implementation then we can drill down some more into the specific tradeoffs which you may want to consider

又怨 2024-12-12 20:06:26

我在生产代码中使用 MongoDB 和存储库模式已有两年多了,我可以说随着时间的推移,它确实对我有帮助。这些抽象非常适合测试(内存中)和生产(MongoDB)。

我使用 Java,代码看起来像这样(大致):

public interface MyStorage {

    boolean add(MyDoc doc);

    boolean update(MyDoc doc);

    boolean remove(String docId);

    boolean commit();

    MyDoc get(String docId);

    MyStorageQuery newQuery();

    List<MyDoc> query(MyStorageQuery q);

}

我为每个存储实现都有一个工厂,它创建 MyDoc 对象的新实例。
我在 MongoDb 和我自己的手动模拟之间交换实现以进行测试。

MongoDB 实现使用 MyDoc 类,该类扩展了 BasicDBObject,如下所示:

public interface MyDoc {
  Data getData(); // let's assume this is a nested doc
  void setData(Data d);
  String getId();
  long getTimestamp();
  void setTimestamp(long time);
}

MongoDbMyDoc extends BasicDBObject implements MyDoc {
  MongoDbObject() { }
  void setId(String id) {
    this.put("_id", id);
  }
  String getId() {
    return super.get("_id");
  }
  void setData(Data d) {
    dataObj = new BasicDBObject();
    dataObj.put("someField",d.someField);
    dataObj.put("someField2", d.someField2);
    super.put("data",dataObj);
  }
  ...
}

然后,我在实际存储实现中使用 MongoDB Java 客户端从数据库返回我的实现的实例。这是我的 MongoDB 存储实现的构造函数:

public MongoDbMyStorage(DB db, String collection) {
  //DB in a mongodb object (from the client library) which was instantiated elsewhere
  dbCollection = db.getCollection(collection);
  dbCollection.setObjectClass(MongoDbMyDoc.class);
  this.factory = new MongoDbMyDocFactory();
}

这里还有 2 个接口:
MyStorageQuery 它也被实现为 MongoDB 实现的 BasicDBObject,并使用存储接口的 newQuery() 生成。
还有 MyDocFactory ,这里没有介绍,但它基本上是一个文档工厂,知道存储实现是什么并相应地生成 MyDoc 实例。

注意事项:
抽象没有多大意义的一件事是定义 MongoDB 存储使用的索引。我将所有 ensureIndex(...) 调用放在构造函数中,不是很通用,但为每个集合定义索引是 MongoDB 特定的优化,因此我可以接受它。
另一个是提交是使用 getLastError() 命令实现的,根据我的经验,该命令效果不佳。这对我来说不是问题,因为我几乎从未明确提交更改。

I use MongoDB in production code with the Repository Pattern for over 2 years now and I can say that it really helped me over time. The abstractions serve well for testing (in-memory) and production (MongoDB).

I use Java and the code looks something like this (roughly):

public interface MyStorage {

    boolean add(MyDoc doc);

    boolean update(MyDoc doc);

    boolean remove(String docId);

    boolean commit();

    MyDoc get(String docId);

    MyStorageQuery newQuery();

    List<MyDoc> query(MyStorageQuery q);

}

I have a factory for each storage implementation which creates new instances of the MyDoc object.
I interchange the implementation between MongoDb and my own hand-rolled mock for testing.

The MongoDB implementation uses a MyDoc class which extends the BasicDBObject like so:

public interface MyDoc {
  Data getData(); // let's assume this is a nested doc
  void setData(Data d);
  String getId();
  long getTimestamp();
  void setTimestamp(long time);
}

MongoDbMyDoc extends BasicDBObject implements MyDoc {
  MongoDbObject() { }
  void setId(String id) {
    this.put("_id", id);
  }
  String getId() {
    return super.get("_id");
  }
  void setData(Data d) {
    dataObj = new BasicDBObject();
    dataObj.put("someField",d.someField);
    dataObj.put("someField2", d.someField2);
    super.put("data",dataObj);
  }
  ...
}

I then in the actual storage implementation use the MongoDB Java client to return instances of my implementation from the DB. Here is the constructor for my MongoDB storage implementation:

public MongoDbMyStorage(DB db, String collection) {
  //DB in a mongodb object (from the client library) which was instantiated elsewhere
  dbCollection = db.getCollection(collection);
  dbCollection.setObjectClass(MongoDbMyDoc.class);
  this.factory = new MongoDbMyDocFactory();
}

There are 2 more interfaces here:
MyStorageQuery which is also implemented as a BasicDBObject for the MongoDB implementation and generated using the newQuery() of the storage interface.
And MyDocFactory which isn't presented here, but it is basically a document factory that knows what the storage implementation is and generates the MyDoc instances accordingly.

Caveats:
One thing where the abstraction doesn't make much sense is in defining the indexes used by the MongoDB storage. I put all my ensureIndex(...) calls in the constructor, not very generic, but defining indexes per collection is a MongoDB specific optimization so I can live with it.
Another is that commit is implemented using the getLastError() command which from my experience didn't work so well. It isn't a problem for me since I almost never explicitly commit a change.

绻影浮沉 2024-12-12 20:06:26

Eric Evens 在他的《领域驱动设计》一书中对存储库模式进行了非常复杂且非常好的解释。他的定义是存储库应该是什么以及应该如何使用它(以我个人的观点)。您可以在此处找到简短说明:Eric Evans 谈存储库

基本上,如果您将存储库保留为客户端代码和工厂之间的中介,那么它们将非常适合我了解您的需求。存储库应该提供查询/构造/验证接口并完成所有数据采集工作(例如连接/查询数据库),并且您应该拥有一个或多个(根据需要)工厂来构建对象并将其传递回客户端通过存储库。

Eric Evens, in his Domain Driven Design book, has a very complex and very good explanation of the repository pattern. His definition is what a repository should be and how it should be used (in my personal opinion). You can find a short description here: Eric Evans on Repositories

Basically, if you keep you repositories just an intermediary between client code and factories, they will be perfect for what I understand you need. The repositories should offer the query/construction/validation interfaces and do all the data acquisition staff (like connect / query database) and than you should have one or more (as needed) factories which will build the objects and pass it back to the client via the repository.

半枫 2024-12-12 20:06:26

使用 NoSQl 数据库的存储库模式比 RDS 数据库更有意义,因为在正确的 DDD 中,每个聚合根需要一个存储库,但由于 RDS 数据存储的限制,开发人员通常为每个实体/表创建一个存储库对象。 NoSQL 数据库允许您正确实现 DDD 和存储库模式。

It makes more sense to use Repository pattern with NoSQl databases than RDS databases because in proper DDD, you need one repository per aggregate root, but dute the limitations of an RDS datastore, devs usually create one repository object per entity/table. NoSQL databases allow you to implement DDD and Repository pattern properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文