【问题标题】:Service-Dao pattern, DTO and relational databaseService-Dao 模式、DTO 和关系数据库
【发布时间】:2015-12-19 02:38:51
【问题描述】:

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

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

Bean 或 Web 服务称为我们所说的“事务层”(封装服务,以便可以通过 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) 我的对象服务

@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 传递给服务类,然后将实体完全传递给 DAO 层?或者我们应该只将参数传递给 DAO,然后它自己创建实体(问题是它会导致一些巨大的方法签名)。

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

【问题讨论】:

    标签: hibernate jpa service dao dto


    【解决方案1】:
    • 在哪里使用 DTO?

    通常,Service 方法获取 DTO 作为参数,并在其实现内部将此 DTO 转换/映射为实体,然后将其传递给存储库。

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

    总而言之,Service 类应该只接受和返回 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,您只需要存储库的接口,也许还需要该接口的实现。如果您愿意,您可以拥有 DAO 并在 Repository 实现中使用它们,但没有必要这样做。他们在参考documentation 上有很好的例子。

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

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

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      当数据跨越“服务/事务层”时,您绝对应该使用 DTO 模式。我写了一个article,讨论了不这样做时出现的一些常见问题,以及如何使用 Blaze-Persistence 实体视图有效地实现 DTO 方法。

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

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

      【讨论】:

        猜你喜欢
        • 2011-02-05
        • 2012-11-22
        • 2021-03-17
        • 2016-09-24
        • 2016-05-06
        • 2017-04-03
        • 2012-09-15
        • 2012-12-31
        • 1970-01-01
        相关资源
        最近更新 更多