Service-Dao模式,DTO和关系数据库

时间:2015-09-22 07:57:50

标签: hibernate jpa service dao dto

首先,如果这个问题已经得到了处理,我很抱歉,但我没有找到我正在寻找的东西。 我正在研究ERP,我们正试图对代码进行一些重构。主要的主题是我们目前不使用任何DAO模式,如果我们需要以不同方式访问“数据库”,这可能是未来的问题。

简而言之,我们的架构将针对这种模式:

Bean或Webservices调用我们称之为“事务层”(封装服务,以便某些东西可以通过WS公开并做其他事情)。该层调用服务,该服务将调用其他服务或DAO。

1)实体

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

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

我的问题是关于最佳做法:

  • 首先,我们使用Hibernate和JPARepository来管理实体。所以我猜测应该在DAOImpls中完成对存储库的调用?那些我们对数据库进行的查询(也就是说JPAQuery有连接,选择等)并做预测?这样DAO将返回DTO ......

  • 我们也不确定在何处使用DTO。这条线应该在“交易层”中使用DTO和DAO中的实体之间?是否应将DTO传递给Service类,然后将实体完全传递给DAO层?或者我们应该只将参数传递给DAO并且它自己创建实体(问题是它会导致一些巨大的方法签名)。

非常感谢,如果需要,请随时提出问题!

2 个答案:

答案 0 :(得分:7)

  • 在何处使用DTO?

通常,Service方法将DTO作为参数获取,并且在其实现中,此DTO被转换/映射到实体,该实体被传递到Repository。

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

总结一下,服务类应该只接受并返回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,反之亦然。您可以将其封装在只进行转换的方法中,甚至可以更好地使用映射库,例如OrikaDozer

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

  • 关于DAO和JPA存储库

如果您使用的是Spring Data JPA repositories,则不需要任何DAO,您只需要一个Repository接口,也许还需要该接口的实现。如果你想要你可以拥有DAO并在Repository实现中使用它们,但是没有必要这样做。他们在参考documentation上有很好的例子。

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

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

希望它有所帮助。

答案 1 :(得分:2)

当数据穿过&#34;服务/交易层&#34;你绝对应该使用DTO模式。我写了article关于不这样做时出现的一些常见问题,以及如何使用Blaze-Persistence Entity Views高效实现DTO方法。

也许您想尝试而不是Orika或Dozer,因为它也会提高您的查询效果。

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