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());
}
}
我的问题是关于最佳实践的:
首先,我们使用Hibernate和JPARepository来管理实体。所以我猜对存储库的调用应该在 DAOImpls 中完成?我们对数据库所做的查询(即具有连接、选择等的 JPAQuery)和投影怎么样?这样 DAO 就会 return DTO...
我们也不确定在哪里使用 DTO。在 "Transaction Layer" 中使用 DTO 和在 DAO 中使用实体之间的界限在哪里?是否应该将 DTO 传递给服务 类 然后将实体完全传递给 DAO 层?或者我们应该只向 DAO 传递参数,它自己创建实体(问题是它会导致一些巨大的方法签名)。
非常感谢,如有需要,请随时提问!
- 在哪里使用 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。
首先,如果这个主题已经被处理过,但我没有找到我想要的东西,我很抱歉。 我正在研究 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());
}
}
我的问题是关于最佳实践的:
首先,我们使用Hibernate和JPARepository来管理实体。所以我猜对存储库的调用应该在 DAOImpls 中完成?我们对数据库所做的查询(即具有连接、选择等的 JPAQuery)和投影怎么样?这样 DAO 就会 return DTO...
我们也不确定在哪里使用 DTO。在 "Transaction Layer" 中使用 DTO 和在 DAO 中使用实体之间的界限在哪里?是否应该将 DTO 传递给服务 类 然后将实体完全传递给 DAO 层?或者我们应该只向 DAO 传递参数,它自己创建实体(问题是它会导致一些巨大的方法签名)。
非常感谢,如有需要,请随时提问!
- 在哪里使用 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。