3
votes

First of all, I'm sorry if this subject has already been treated but I didn't find what I was exactly looking for. I'm working on a ERP and we're trying to make some refactoring of the code. The main subject is that we currently don't use any DAO pattern, which could be a problem in the future if we need to access the "database" differently.

In brief, our architecture would aim to this pattern :

Bean or Webservices call what we call the "Transaction Layer" (encapsulates Services so that some stuff can be exposed via WS and do other things). That layer calls the Services, that will call other Services or DAOs.

1) Entity

public class MyObject{
    private String arg1;
    private List<SomeOtherObject> arg2List;

}

2) DAO

public interface MyObjectDAO {
    void save();
    List<MyObject> findAllObjects();
   // Some other queries
   // ...
}

3) MyObjectService

@Service
public class MyObjectService{
    @Autowired
    MyObjectDAO dao;

    @Autowired
    MyOtherObjectDAO otherDao;

    public void createObject(String arg1Dto, List<MyOtherObjectDto> arg2Dto){
       // How to deal with arg 2 ? 


        MyObject obj = new MyObject();
        obj.setArg1(arg1);
        obj.setArg2(myEntityRepresentingArg2);
        dao.save(obj1);
    }
}

3) Transaction Layer

public class{
    // Many many things...

    //Method called from the Beans
    @Transactional(rollbackFor=Exception.class)
    public void serviceCall(SomeDto arguments){
        myObjectServices.createObject(arguments.getArg1(), arguments.getArg2());
    }
}

My question is about best practices :

  • First of all, we use Hibernate and JPARepository to manage entities. So I'm guessing the call to repositories should be done in DAOImpls ? What about the queries we do to the database (that is to say JPAQuery with joins, selects, etc) and do projections ? That way the DAO would return DTOs...

  • We are also not sure on where to use the DTOs. Where the line should be between the use of DTO in the "Transaction Layer" and the entities one in DAOs ? Should the DTO be passed to the Service classes and then pass entirely the entities to the DAO layer ? Or should we pass only arguments to the DAO and it creates the entities itself (the problem is that it leads to some enormous method signatures).

Thank you very much and do not hesitate to ask questions if needed !

2

2 Answers

8
votes
  • Where to use the DTOs?

Usually a Service method gets a DTO as a parameter and inside its implementation this DTO is transformed/mapped into an entity, which is passed to the Repository.

Repositories (or DAOs) should only know about entities, not DTOs, and other layers should only know about DTOs, not entities.

To sum it up, Service classes should only take and return DTOs. This is done to hide the model and its details outside of the persistence layer. Example:

public class ProjectService {
    // The Repository should be an interface and Spring injects your Impl
    @Autowired
    private ProjectRepository projectRepository;

    public void createProject(ProjectDto dto) {
        // We map the Dto into an Entity
        Project project = new Project();
        project.setName(dto.getName);
        project.setDepartment(dto.getDepartment);        

        projectRepository.save(project);
    }

    public ProjectDto findProject(Long id) {
        // Get Project entity
        Project project = projectRepository.findOne(id);
        // Map entity to dto
        ProjectDto dto = new ProjectDto();
        dto.setName(project.getName());
        dto.setDepartment(project.getDepartment());

        return dto;
    }
}

As you see there will be a lot of boilerplate for mapping entities to dto's and viceversa. You can encapsulate it in methods that will just do the transformation or even better you can use a mapping library such as Orika or Dozer.

Here is an example of how to use Orika and integrate it with Spring if you need to.

  • About DAOs and JPA repositories

If you are using Spring Data JPA repositories you don't need any DAO, you just need an interface for the Repository and maybe an implementation for that interface. If you want you can have DAOs and use them in the Repository implementation but there's no need to do that. They have good examples on their reference documentation.

For executing SQL queries you can use @Query. It can take JPQL or native SQL queries when nativeQuery=true. You can find more info here.

  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?0", nativeQuery = true)
  User findByEmailAddress(String emailAddress);

Hope it helped.

2
votes

When the data crosses the "service/transaction layer" you should definitely make use of the DTO pattern. I have written an article on some of the common problems that arise when not doing this and also how you can efficiently implement a DTO approach with Blaze-Persistence Entity Views.

Maybe you want to give that a try instead of Orika or Dozer as it will also improve the performance of your queries.

If you have Spring Data JPA repositories you shouldn't require a separate DAO anymore.