使用 ORM 时如何实现命令查询分离 (CQS)?

发布于 2024-08-02 09:26:34 字数 318 浏览 2 评论 0原文

CQS 架构模式背后的原则是将查询和命令分离到不同的路径中。理想情况下,您的持久性存储可以进行读/写分区,但就我而言,只有一个标准化数据库。

如果您使用 ORM(在我的例子中为 NHibernate),那么很明显,在发出命令时会使用 ORM。但是,您需要运行为用户屏幕塑造数据 (DTO) 的所有各种查询呢?在执行 CQS 的查询端时放弃 ORM 是常见做法吗?

我应该在哪里实施查询和 DTO 预测?直接 ADO.NET(数据读取器、dtos、数据表、存储过程)?有些查询非常独特,涉及大量连接以将所有内容组合在一起。我不想对查询的数据库进行非规范化,但我可以创建视图(穷人的非规范化)。

The principle behind the CQS architectural pattern is that you separate your queries and commands into distinct paths. Ideally, your persistence store can be read/write partitioned, but in my case, there is a single, normalized database.

If you are using an ORM (NHibernate in my case), it's clear that the ORM is used when issuing commands. But what about all the various queries you need to run to shape data (DTOs) for user screens, is it common practice to ditch the ORM when doing the Query side of CQS?

Where should I implement my queries and DTO projections? Straight ADO.NET (datareaders, dtos, datatables, stored procs)? Some queries are quite unique and involve a lot of joins to pull everything together. I don't want to denormalize the database for the queries, but I could create views (poor man's denormalization).

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

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

发布评论

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

评论(5

天赋异禀 2024-08-09 09:26:34

我假设 CQS 您指的是 DDD 架构模式,又名 CQRS,并非严格意义上的传统CQS 原则。

我仍然会使用 NHibernate 作为您的只读模型。有许多优点,例如未来查询和多重查询、延迟/渴望加载等......这将优化数据库的闲聊性。此外,如果 UI 允许用户从本质上更改 where 子句,那么使用 ORM 编写查询将会更容易。

关于如何从技术上处理只读模型,您可以使用 NHibernate 将实体标记为不可变。您可以简单地将所有读取模型实体标记为不可变。另外,我不认为你可以更新 NHibernate 中的投影,因此这是作为你的只读模型的另一种选择(如果我错了,请有人纠正我,因为我不是 100% 确定)。

关于丑陋或不可能的 NH 映射:NH 可以映射到视图和存储过程,所以我认为在需要时使用它们会很好。对于只读场景,视图可能比存储过程更灵活,因为您的 SQL 仍然是动态的。但是,如果您需要读取/写入任何这些扁平结构,我将映射到存储过程。

I'm assuming by CQS you mean the DDD architectural pattern aka CQRS, not strictly the traditional CQS principle.

I'd still use NHibernate for your read only model. There are many advantages such as future and multi queries, lazy/eager loading etc... that will optimize DB chattiness. Additionally, it will be easier to compose queries with an ORM if the UI allows for the user to essentially change the where clause.

Regarding how to technically handle a read only model, you can mark an entity immutable with NHibernate. You could simply mark all of your read model entities immutable. Also, I don't think you can update projections in NHibernate so that is another option to go for as your read only model (Someone please correct me if I am wrong as I am not 100% sure).

Regarding ugly or impossible NH mappings: NH can map to views and stored procedures, so I think it would be fine to use these when you need to. Views are probably a bit more flexible than stored procedures for a read only scenario because your SQL will still be dynamic. However, If you need read / write for any of these flattened structures I'd map to a store procedure.

何以心动 2024-08-09 09:26:34

最终,我们的想法是,您应该使用使查询通道最容易构建和维护的任何方式。您不再需要担心更新、执行业务规则、维护数据完整性,甚至处理负载(在大多数情况下)。因此,您可以自由选择许多以前没有的选项。

但 NHibernate 仍然是一个不错的选择……它只是不再是自动默认值(有时是命令端的默认值)。

我们选择使用 Castle Active Record(它在底层基于 NHibernate),主要是因为它有一个很好的功能,可以从类中为您生成一个表。这非常适合我们,因为这是我们的工作流程:首先,我们创建一个 ViewModel 类。这个类完全是为了视图的需要而设计的。然后,我们使用 Castle Active Record 属性标记该 ViewModel。然后,我们要求 Active Record 在查询数据库中生成该类的相应表。这是我们发现的快速获取为 ViewModel 类提供服务的查询数据库表的最快、最流畅的方法。自动生成反映了这样一个现实:表存在的唯一原因是为视图提供服务。

Ultimately, the idea is that you should use whatever makes the Query channel easiest for you to build and maintain. You no longer have to worry about updates, enforcing business rules, maintaining data integrity, or even handling load (for the most part). So you're free to choose many options that were previously not on the table.

But NHibernate can still be a good option ... it's just no longer the automatic default (which it sometimes is for the Command side).

We've chosen to use Castle Active Record (which is based on NHibernate under the hood), mainly because it has a nice feature that will generate a table for you from a class. This fits excellently for us, because here's our workflow: First, we create a ViewModel class. This class is shaped entirely for the needs of the View. Then, we mark that ViewModel with Castle Active Record attributes. Then, we ask Active Record to generate the corresponding table for that class in the Query database. This is the fastest, smoothest way we have found to quickly get a Query database table that serves the ViewModel class. The automatic generation reflects the reality that the only reason the table exists is to serve the view.

源来凯始玺欢你 2024-08-09 09:26:34

我们使用 EF 作为命令部分,并直接使用 ADO.NET =>用于查询链的 DTO。优点:

1) 能够优化 SQL 查询并使用未抽象到 ORM 层的高级数据库存储功能

2) 开销更少

但我们仅对要求较高的部分(搜索)使用分离,其余部分依赖于常见的实体框架模型。

We're using EF for the command part, and straight ADO.NET => DTOs for query chain. Advantages:

1) Ability to optimize SQL queries and use advanced DB store features not abstracted into ORM layer

2) Less overhead

But we're using the separation only for demanding parts (search), the rest relies on common Entity Framework model.

抠脚大汉 2024-08-09 09:26:34

无需使用不同的方法来读取数据库与更新数据库。 CQS 只是指出更新数据存储的命令应该与从数据存储读取状态的查询分开。

您仍然可以使用 NHibernate 从数据存储中读取数据,但您可能希望通过创建两个不同的类来封装数据访问来使其显而易见。一个类将具有读取(查询)数据存储的方法,另一个类将具有向数据存储发出命令(添加、更新、删除)的方法。

您要避免的是从数据库获取消息,然后将该消息标记为在数据库中已读的方法。这应该是两个不同的方法调用。您不应更改状态并从同一方法返回值。

There isn't a need to use a different approach to reading your database vs. updating your database. CQS simply states that commands that update the data store should be separate from the queries that read state from the data store.

You can still use NHibernate to read from your data store, but you might want to make it obvious by creating two different classes to encapsulate your data access. One class would have methods to read (query) the data store, the other class would have methods to issue commands (add, update, delete) to the data store.

What you are trying to avoid is a method that gets a message from the database, and then marks the message as read in the database. This should be two distinct method calls. You should not change the state and return a value from the same method.

坦然微笑 2024-08-09 09:26:34

我喜欢将 ORM 的读取和写入分开,因此我会使用(并且我使用):

Nhibernate 用于命令 - 精美地映射我的域模型

Dapper.net 用于查询 - 精美映射我的 DTO,并在查询过于复杂时提供灵活性。

他们就像汉·索罗和楚巴卡一样是完美的情侣。

I like to keep ORM's separate for reads and writes so I would use (and I use):

Nhibernate for commands - beautifully maps my domain model

Dapper.net for queries - beautifully maps my DTO's and allows felxibility if the query is too complex.

They are a perfect couple just like Han Solo and Chewbacca.

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