DDD, domain entities/VO and JPA
Asked Answered
M

2

23

I'm starting with DDD and you can image my brain is boiling.

My question is related to my domain objects (entities, VO, ...) which represents my domain concepts/logic and how to persist/retrieve them.

The blue book says the repository is a way to represent collections on domain objects and is responsible to communicate with the infrastructure layer. I read also at some post the infrastructura layer is where you must use hibernate, JPA or whatever.

Then I see this Spring-data-jpa example http://spring.io/guides/gs/accessing-data-jpa/ and I become crazy.

The slogan say Spring-data-jpa is to create repositories easily and the previous samples seems to merge JPA annotations into a domain object (the customer).

Is the sample right? or Am I right?

If I'm right and the domain and infrastructure must be separated, that means to store a customer I must have:

  • a Customer class in my domain layer (that represents a customer and has all the logic operations)
  • a CustomerRepository un my domain layer (that retrieves or stores customers from infrastructure layer)
  • a Customer class in infrastructure layer, probably annotated with @Entity
  • Some CustomerReposityJPA that know how to store/retrieve customers from database.

Thanks for any clarification.

Myrtice answered 14/7, 2015 at 7:34 Comment(1)
Domain driven design.Cognac
G
17

In DDD, a repository is an object that participates in the domain but really abstracts away some backing store.

If you annotate your domain objects with JPA annotations, your persistence mechanism has bled into your domain. You have tied your domain structure to your persistence structure which is not ideal.

Your JpaCustomerRepository (implements ICustomerRepository) could map the unannotated domain classes (Customer) into an annotated JPA representation - JPA customer. This keeps the annotations out of your domain classes, so is cleaner. It allows you to vary the JPA persistence structure independently of your domain structure. The cost for this benefit is the complexity of the mapping code.

interface ICustomerRepository {}

class JpaCustomerRepository implements ICustomerRepository {
     void save(Customer customer) {
          JpaCustomer jpaCustomer = map(customer);
          save(jpaCustomer);
     }
}

class Customer {}

class JpaCustomer {}
Globular answered 15/7, 2015 at 9:38 Comment(5)
The cost is high, there is duplication of code: Two customer classes whose properties need to be mapped. Sounds like a lot of boilerplate code. How likely is the substition of the JPA provider to justify the added effort?Labialized
I consider JPA Annotations as declarative information. In case that you need to substitute your JPA provider, how hard is it to remove JPA Annotations from your domain entities?Await
"The cost is high, there is duplication of code" - it is a duplication of code if the DDD Customer is the same as the dumb JPA Customer entity. But DDD Customer is supposed to be an object with a real behaviour and not a fake object as the JPA entity (which usually contains just fields + getters/setters + ORM annotations).Hormuz
I'm applying the same concept. My entire domain model is free of framework specific annotations and is completely persistence agnostic. But how would you solve following situation where mapping is done between domain and data object while keeping track which object is added / removed from an existing collection? https://mcmap.net/q/586291/-aggregate-to-jpa-entity-mapping/2054927Sismondi
I agree, the main advantage of keeping JPA out of the domain is not that the domain is independent of persistence technology but that it is independent of persistence structure. That will allow you to use inheritance and patterns like Aggregate and Strategy in your domain objects, instead of working with one-to-one representations of database entries.Fairley
C
3

I can't see the link you've posted and I have never apply Domain driven design to the Java world. Theoretically what you need is Customer aggregate in the domain layer. In your domain layer there's space for the repository (intended as interface), so you'll have ICustomerRepository. Probably you will have the four prototype for the common persistence issues:

GetById(CustomerId id);
Add(Customer c);
Delete(Customer c);
Update(Customer c);

In the infrastructure layer you will provide the body (for instance CustomerRepository), in the infrastracture layer you can couple yourself with something technological (for example JPA).

Domain layer MUST be completly unaware of technology used in the infrastructure. Doing so you could change completly the implementation details having (almost) no troubles.

Cognac answered 14/7, 2015 at 8:41 Comment(1)
Has anyone actually seen an example project that does this? I can't seem to find any samples that actually have domain entities (not necessarily related to the DB tables) modeled in the domain layer and then in the infrastructure layer, JPA @Entity objects that map to db tables. The repository interfaces should get implemented in that infrastructure module and should know how to map between the JPA entities into the domain models.Bolanos

© 2022 - 2024 — McMap. All rights reserved.