Information About DDD Transaction Management

Asked 2 years ago, Updated 2 years ago, 64 views

DDD recognizes transaction management at the application layer.

For example, there are two domain models: User and Company. Let's say that each of them has a DB registration process on the master screen.

when registering with an application class of service
class UserRegisterService{
    public function register (User$user)
    {
        // transaction initiation
        try{
            // user registration processing
           $this->userRepo->register($user);
            commit
        } catch{
            rollback
        }
    }
}

classCompanyRegisterService{
    public function register (Company$company)
    {
        // transaction initiation
        try{
            // company registration processing
            $this->companyRepo->register($company);
            commit
        } catch{
            rollback
        }
    }
}

I'm afraid I'll write like this

If there is another job X that registers User and Company at the same time here
UUserRegisterService 「 and anCompanyRegisterService <
in X class of service If you call
after registering the user, even if there is an error in registering the company. Naturally, only CompanyService rolls back.

However, even if you write exactly the same process as the two classes of service in the X class of service,
It's going to be a redundant code...
What should I do in this case?

Dear Vietta Toe,

I am very sorry that the code of the sample has been omitted a lot, but
The actual query is issued by a class called Repository.(I edited the sample code)
In other words, the processing flow is as follows:
View→Controller→Service→Repository→DB

Simple as the code in the sample
I think all you have to do is call userRepo and companyRepo among the register methods of X class of service.

In the actual business, after processing data for registration within the service class, etc. Often, the repository is called using processed data as an argument.

In that case, if you write data processing using the register method of X class of service,
You will end up writing the same thing for X and User services.

Therefore, I would like to call the class of service as much as possible.
Should I leave transaction management to the layer above the class of service?

At that time, as Vietta Toe pointed out, will the controller manage transactions?
Or create one layer between the controller and the service, and then do transactions there?
What should I do?

I'm sorry for my poor explanation.I wish it could be conveyed...

php database

2022-09-30 19:49

3 Answers

I don't know about DDD itself, so generally speaking

Is it due to insufficient partitioning of the entity?

In the example, issuing queries and starting and ending transactions are handled at the same level, which is troubling.The transaction manager should manage the transaction scope.In the example, the scope is captured for each function of the register.This is fine as long as the policy regarding the scope is correct, but the scope was not appropriate because it was a real problem.
One way to do this is to create a higher class for transaction management.(Typically, this is what the framework defines.)
In the transaction manager, a transaction is started and a query is issued (called) in the register here, and if there is no problem, the transaction manager commits.Of course, he will be responsible for the rollback.That's what it looks like.


2022-09-30 19:49

It's DDD, right?
If you are following DDD's development design philosophy, are you using MVCorREST?

Either way,

And as you said

You may create a higher class for transaction management.


for these designs: Routing and controller and model, or controller and model, are required to be designed in two layers.

In this case, the controller is the best way to issue transactions.

The controller controls the creation, editing, and updating of the model. The model defines controls.

Transactions are not included in the feature, and the controller issues transactions before starting model operations, checks transactions after editing the model, performs rollback/commit operations, and so on, and finishes basic operations.

Therefore, more than one layer is required.

controller▼

use model\Company;
use model\User;

US>class controller { 

    public function New($db){
        // transaction issue
        $db->Begin();

        // Company Data Creation
        $cm=Company::Register("HOGE-0000", "HOGE CORPORATION";
        $company=$cm->Create($db);
        if($company["Error"]){
            $db->Rollback();
            printf($company["Error"]);
            return false;
        }   

        // User Data Creation
        $um=User::Register("fuga000", "Fuga Fumie", "FUGA-981738271");
        $user=$um->Create($db);
        if($user["Error"]){
            $db->Rollback();
            printf($user["Error"]);
            return false;
        }  

        // commit
        $db->Commit();
        return true;
    }
}
new Controller();
?>

Model▼

<?php namespace model;
US>class Company {

    // Structure
    public$id;
    public$name;
    public$createdAt;
    public$updatedAt;
    public$deletedAt;

    // Structure Register
    public function Register($id,$name){
        $this->id=$id;
        $this->name=$name;
        $this->createdAt=date("Y-m-d H-i-s");
        $this->updatedAt=date("Y-m-d H-i-s");
        $this->deletedAt=null;
    }

    public function Create ($DB) {
        // Processing of creation (describe given encryption or DML operations)
        $resp = $DB->Set("tbl_company_mst") ->Query(
            array($this->id,$this->name,$this->createdAt,$this->updatedAt,$this->deletedAt)
        )->Do();

        if($resp->Error()){
            return array("Company"=>new Company(), "Error"=>$resp->Error());
        }

        $c = Company::Register($this->id,$this->name);

        return array("Company"=>$c, "Error"=>null);
    }

    public function Read ($DB) {
        // Processing of creation (describe given encryption or DML operations)
    }

    public function Update ($DB) {
        // Processing of creation (describe given encryption or DML operations)
    }

    public function Delete ($DB) {
        // Processing of creation (describe given encryption or DML operations)
    }
}
?>

<?php namespace model;
class User {
    public$id;
    public$name;
    public$employNo;
    public$createdAt;
    public$updatedAt;
    public$deletedAt;

    public function Register($id,$name,$employNo){
        $this->id=$id;
        $this->name=$name;
        $this->employNo=$employNo;
        $this->createdAt=date("Y-m-d H-i-s");
        $this->updatedAt=date("Y-m-d H-i-s");
        $this->deletedAt=null;
    }

    public function Create() {
        // Processing of creation (describe given encryption or DML operations)
    }

    public function Read() {
        // Processing of creation (describe given encryption or DML operations)
    }

    public function Update() {
        // Processing of creation (describe given encryption or DML operations)
    }

    public function Delete() {
        // Processing of creation (describe given encryption or DML operations)
    }
} 
?>

この This example uses its own ORM as an example, so it does not work in a copy.


2022-09-30 19:49

I don't know what kind of framework you are using, so I don't know if it's appropriate, but
I believe that the content described in 〇 Ser Service is not an application layer, but a domain layer.If you have Eric Evans' "Domain Driven Design," it is equivalent to the "Services" section of this book.
In my case, the application layer will cover the use case on a screen or page basis, so if both User and Company are required, I will write both.It's called 〇 M Model.
The layers are as follows.

Controller→ ApplicationModel→DomainModel (Entity, ValueObject, Service, Repository)→ DataAccess

Excuse me for answering an old question.


2022-09-30 19:49

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.