0

I am refactoring a project to bring it closer to DDD. The project is written in VB.Net and use WinForms to UI. I have been learning about DDD and I still don't have some things very clear.

I use the repository pattern and SqlKata to create and execute SQL Sentences. I read about why transactions should be handle in Application Services, but I think about some cases which to handle transaction in repositories could be a good idea. An example:

A domain model Order with a list property Lines. A service called FindOrderService. The service use the OrderRepository and its function .FindById(...). This repository return Order with its Lines. In Database Order and OrderLines are two different tables.

I. Shouldn't the repository function handle a transaction by having to use two tables to make sure the domain object is created in a consistent state? With a function .Add(...) Wouldn't the same thing happen?

II. Application services may or may not be used in a transactional manner. But they don't know how many tables are used to persist an Aggregate. Wouldn't ensuring something like this be a matter of Infrastructure even though it can also be handled from the application services?

III. From what I've read. It seems that exist two terms: "Bussines transaction" and "Technical transaction" (in this post). Are this exaples technical transactions?

Thanks in advance!

Edit:

My question, more specifically, is: if the Application Services can choose whether the service itself can initiate the Transaction from the database or not, how can it be ensured from the Repositories (if they use more than one table) that the Domain Model that must be returned or persisted is consistent?

I think in this post has been spoken about this question more in detail. This response is close to the one I am looking for, but is not clear if can be used the database transaction in the repository or how to handle this properly.

Jaime
  • 45
  • 8

1 Answers1

1

I read about why transactions should be handle in Application Services, but I think about some cases which to handle transaction in repositories could be a good idea.

The fact that a specific scenario allows to have things done in two different ways does not mean we should choose the "rule breaker" way: having a single repository in the context of a transaction does not justify making the repository own the transaction. A transaction should span over one or more repositories by design.

I. A transaction can be abstracted away in application level, yet "contain" a single repository that queries/updates two tables in order to keep consistency.

II. Transactions, repositories, aggregates - all of them should be abstracted away in application level. True, infrastructure level is where you create concrete implementations (technical transaction, several tables, some entities), but application does not care that a single unit-of-work (transaction) spans over four repositories which actually "hide" eight tables.

III. Business transaction and technical transaction can overlap, but don't have to. For example, you can have a business process within which multiple technical transactions are executed (a single process may operate on different databases), composing together a single business transaction.

Update:

It is indeed recommended to have a 1:1 relation between an aggregate and a transaction, however an aggregate may embed other non-aggregate entities namely local entities (e.g. an order and its order-lines), in a one-to-many manner, which can be naturally reflected as two table in DB (parent table, child table). So obviously multiple tables may be updated in the context of one transaction in order to keep a domain model consistent.

It makes sense to identify the term "repository" with a data-store engine capable of tracking a set of changes and commit/undo them at once. But more important, a repository in the context of code is an abstraction for an object communicating with such store, and one can decide to have by design two repository interfaces: one for parent table (IOrder), second for child table (IOrderLine).

A repository is not responsible for supplying guarantees about domain model's consistency. Repositories are just interfaces for communicating against data-stores, and the application layer is responsible for proper orchestration, i.e. scoping one or more repository interfaces into a single unit-of-work (e.g. a transaction). An application service defines the business flow using the tools supplied by the domain model, be it a single repository interface persisting two table or two repository interfaces each persisting one table.

desertech
  • 911
  • 3
  • 7
  • In first place, thanks you for you response. It's still difficult for me understand this and explain my doubts as well as I would like. Please, tell me if I've understood your response: I've heard in videos and read in articles a Transaction only can handle one Aggregate, therefore one Repository. This rule is the reason I don't understand your second (II) response. (Continue...) – Jaime Oct 29 '21 at 10:19
  • [...] My question, more specifically, is: if the Application Services can choose whether the service itself can initiate the Transaction from the database or not, how can it be ensured from the Repositories (if they use more than one table) that the Domain Model that must be returned or persisted is consistent? My idea was this: from Repositories check if the Transaction hasn't been begun then the Repository begin the Transaction. The Application Service shouldn't begin the Transaction only for the fact that Repository needs use more than one table, because it don't know this. – Jaime Oct 29 '21 at 10:28