Joel Min
Joel Min

Reputation: 3457

DDD - How does the domain receive client data

I'm planning to refactor a legacy .NET project that I'm maintaining, there are mainly 4 projects involved:

When user submits a form to update a person's details, the process looks somewhat like this:

  1. Using the submitted data, controller constructs a PersonDetailsDTO which consists of multiple simple fields to hold FirstName, LastName, Age and etc, and a complex type object called AddressDTO that holds address details: var dto = new PersonDetails(...);
  2. Controller calls the service layer with the DTO:

    _personService.UpdateDetails(dto);
    
  3. In the service:

    public void UpdatePerson(PersonDetailsDTO dto)
    {
        var person = _personRepository.GetById(dto.PersonId);
        person.Update(dto);
        _personRepository.Update(person);
    }
    
  4. In the Person domain:

    public class Person : AggregateRoot
    {
        private string FirstName;
        .... // other fields
        private Address Address;
    
        public void Update(PersonDetailsDTO dto)
        {
            FirstName = dto.FirstName;
            .... // other fields
            Address.Update(dto.AddressDTO); // update the value object - address
        }
    }
    

As you can see here, the Person domain references the PersonDetailsDTO. This feels wrong to me as DTOs are means to present the data in the domain to its clients while not exposing the domain itself. and the domain should not be concerned with how it's presented to the clients.

Also IMO the DTOs should live in the My.Company.Service project as it's the service that defines the operation/data transfer contracts.

But then how would the service pass the details on to the domain? Would it have to be a loooong list of parameters: person.Update(firstName, lastName, age, gender, street1, street2, state, postcode...). This certainly looks wrong to me.

Or does the domain have to define yet another set of it's own "DTOs" to receive client data?

I have gone through a LOT of tutorials and SO posts and no one seem to share my concern, so I'm starting to think I'm missing something here, could someone point me to the right direction?

Upvotes: 0

Views: 540

Answers (3)

Polymorphic
Polymorphic

Reputation: 430

You need to implement Object to Object mapping. It means that Service layer is responsible for creating and populating domain objects based on DTO by mapping values from the DTO instance received from client.

You can take advantage of Automapper library to simplify object-to-object mapping. Of course it can be served for domain to DTO if needed.

Upvotes: 1

msmani
msmani

Reputation: 720

You could do as follows. You already have a Value Object named Address similarly you could have another Value Object as PersonalDetails which will contain firstName, lastName, age, gender etc. and the Person entity will have two behaviors like updatePersonalDetails() and updateAddress(). Your application service will look like below.

public void UpdatePerson(PersonDetailsDTO dto)
{
    var person = _personRepository.GetById(dto.PersonId);
    Address address = new Address(dto.getStreet1, dto.getStreet2,...);
    PersonalDetails details = new PersonalDetails(dto.getFirstName,dto.getLastName(),...);
    person.updatePersonalDetails(details);
    person.updateAddress(address);
   _personRepository.save(person);
}

Upvotes: 1

Constantin Galbenu
Constantin Galbenu

Reputation: 17683

According to the Dependency inversion principle and DDD, the Value objects (the DTOs as you call them: PersonDetailsDTO and Address) should be owned by the Domain. This means that they should reside in the Domain namespace/package/project. And BTW, those Value objects can be used all the way up to the Presentation layer and back.

Secondly, they are not DTOs (Data transfer objects) because there is no expensive remote call involved, but Value objects (cohesive data and possible behavior); read more here how to not use them as an anti-pattern.

Last but not least, you should name your methods with terms from the Ubiquitous language (person.Update does not seem to be from the UL). I'm not saying 100% that is your case because I don't know your domain, I'm just saying that you should pay attention to these important details (naming things).

Upvotes: 2

Related Questions