Reputation: 1925
In my current struggle with DDD in a Spring Boot application,I'm in an impasse. I know my domain entities should not have any connection with the infrastructure layer (Where the Hibernate entities live). Of course, my domain layer relies in the data of the Hibernate entity to do it's operations.
So in my application layer, my services load the Hibernate entity and pass it along in the domain entity.
Here is an example of my domain entity:
package com.transportifygame.core.domain.objects;
import com.transportifygame.core.domain.OperationResult;
import com.transportifygame.core.domain.constants.Garages;
import com.transportifygame.core.domain.exceptions.garages.NotAvailableSpotException;
import com.transportifygame.core.infrastructure.entities.CompanyEntity;
import com.transportifygame.core.infrastructure.entities.GarageEntity;
import com.transportifygame.core.infrastructure.entities.LocationEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
public class Garage {
private GarageEntity garage;
public static Integer getAvailableSlots(Garages.Size size) {
switch (size) {
case SMALL:
return Garages.Slots.SMALL;
case MEDIUM:
return Garages.Slots.MEDIUM;
case LARGE:
return Garages.Slots.LARGE;
case HUGE:
return Garages.Slots.HUGE;
}
return 0;
}
public static Double getGaragePriceToBuy(Garages.Size size) {
switch (size) {
case SMALL:
return Garages.Prices.BUY_SMALL;
case MEDIUM:
return Garages.Prices.BUY_MEDIUM;
case LARGE:
return Garages.Prices.BUY_LARGE;
case HUGE:
return Garages.Prices.BUY_HUGE;
}
return 0.0;
}
public static OperationResult<GarageEntity, Object> buy(
Garages.Size size,
CompanyEntity company,
LocationEntity location
) {
// As we had changed the company object, we have to refresh
var newGarage = new GarageEntity();
newGarage.setCompany(company);
newGarage.setLocation(location);
newGarage.setSize(size.ordinal());
newGarage.setSlotsAvailable(Garage.getAvailableSlots(size));
return new OperationResult<>(newGarage, null);
}
public static void hasAvailableSpot(GarageEntity garage) throws NotAvailableSpotException {
if (garage.getSlotsAvailable() == 0) {
throw new NotAvailableSpotException();
}
}
public static OperationResult<GarageEntity, Object> addFreeSlot(GarageEntity garage) {
garage.setSlotsAvailable(garage.getSlotsAvailable() - 1);
return new OperationResult<>(garage, null);
}
public static OperationResult<GarageEntity, Object> removeFreeSlot(GarageEntity garage) {
garage.setSlotsAvailable(garage.getSlotsAvailable() + 1);
return new OperationResult<>(garage, null);
}
}
Now the question is, is this the right way to feed the domain entity needed data? If not, what is the right way?
Is it using factories to build the domain entity based in the hibernate entity? And the domain entity should mirror the hibernate entity properties?
I also have read that some people use the approach to add the logic of the domain entity in the Hibernate entity, but I think that's not the right way to do it.
Upvotes: 0
Views: 1073
Reputation: 428
I would recommend to get familiar with DDDs Repository Pattern. In short a repository should mimic an in-memory collection to retrieve and store your domain objects.
So you could end up designing your application with hibernate two ways:
write a high-level repository interface that exposes "find", "save", etc for your domain entity. the repository interface and the returned entities should be "pure domain logic". that is: no persistence or hibernate concerns. in your case it would be the Garage
object with all business methods implemented there.
within the repository implementation (which may reside in another layer/package) you would deal with hibernates row represenation (hibernate entities) and the entity manager to get the contract of the interface done. in your case this is where the Garage
object gets mapped to the (dumb) GarageEntity
and persisted via EntityManager
or Session
.
you may accept some leakage of persistence/hibernate into your domain. that would result in having a single Garage
domain object, which contains all business logic AND hibernate/jpa annotations (or xml) on the same source file (xml could be separate). the repository may in this case be a direct jpa repository implemantation.
in any case the logic in DDD is always the same:
in the application service (some GarageService
- entry point of the use case) the repository is queried for the domain object on which a business operation is performed on. then the application service stores the modified entity again in the repository.
Upvotes: 1