Service-Dao模式、DTO与关系型数据库

Service-Dao pattern, DTO and relational database

首先,如果这个主题已经被处理过,但我没有找到我想要的东西,我很抱歉。 我正在研究 ERP,我们正在尝试对代码进行一些重构。主要问题是我们目前不使用任何 DAO 模式,如果我们需要以不同方式访问 "database",这在未来可能会成为问题。

简而言之,我们的架构将以这种模式为目标:

Bean 或 Webservices 调用我们所说的 "Transaction Layer"(封装服务,以便一些东西可以通过 WS 公开并做其他事情)。该层调用服务,服务将调用其他服务或 DAO。

1) 实体

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

}

2) 道

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

3) 我的对象服务

@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) 交易层

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());
    }
}

我的问题是关于最佳实践的:

非常感谢,如有需要,请随时提问!

  • 在哪里使用 DTO?

通常,服务方法获取 DTO 作为参数,在其实现中,此 DTO transformed/mapped 进入一个实体,该实体被传递到存储库。

存储库(或 DAO)应该只知道实体,而不是 DTO,其他层应该只知道 DTO,而不是实体。

总而言之,服务 类 应该只接受和 return DTO。 这样做是为了将模型及其细节隐藏在持久层之外。示例:

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;
    }
}

如您所见,将有很多用于将实体映射到 dto 的样板文件,反之亦然。您可以将它封装在只会进行转换的方法中,或者更好的是您可以使用映射库,例如 Orika or Dozer.

Here 是如何使用 Orika 并将其与 Spring 集成的示例。

  • 关于 DAO 和 JPA 存储库

如果您正在使用 Spring 数据 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

要执行 SQL 查询,您可以使用 @Query。它可以在 nativeQuery=true 时采用 JPQL 或本机 SQL 查询。您可以找到更多信息 here.

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

希望对您有所帮助。

当数据跨越 "service/transaction layer" 时,您绝对应该使用 DTO 模式。我已经写了一篇 article 关于不这样做时出现的一些常见问题,以及如何使用 Blaze-Persistence 实体视图有效地实现 DTO 方法。

也许您想尝试一下,而不是 Orika 或 Dozer,因为它也会提高查询的性能。

如果您有 Spring 个 Data JPA 存储库,您将不再需要单独的 DAO。