如何在 Spring JPA 中将 Optional<Entity> 转换为 Optional<EntityDTO>?
How to convert Optional<Entity> to Optional<EntityDTO> in Spring JPA?
我是 Spring 的新手,虽然我可以将域实体转换为 List<Entity>
,但我无法将它们正确转换为 Optional<Entity>
。我在存储库和服务中有以下方法:
EmployeeRepository:
@Query(value = "SELECT ...")
Optional<Employee> findByUuid(@Param(value = "uuid") final UUID uuid);
员工服务:
@Override
@LogExecution
@Transactional(readOnly = true)
public Optional<EmployeeDTO> findByUuid(UUID uuid) {
Optional<Employee> employee = employeeRepository.findByUuid(uuid);
return employee
.stream()
.map(EmployeeDTO::new)
// .orElse(null);
//.findFirst(); /// ???
}
我的问题:
1.我应该如何正确地将Optional<Employee>
转换为Optional<EmployeeDTO>
?
2.是否Spring JPA
收集SELECT
子句中的字段,并在service方法中映射到对应的DTO
匹配他们的名字?如果是这样,它是否维护命名,例如employee_name
到 employeeName
在数据库 table 和领域模型 class?
employeeRepository#findByUuid
的输出 Optional<Employee>
和方法输出类型 Optional<EmployeeDTO>
之间发生的映射是 1:1,所以这里不涉及Stream
(调用stream()
)。
您只需将 Employee
的字段正确映射到 EmployeeDTO
。处理从 employeeRepository#findByUuid
返回的 Optional
实际上为空的情况可以留在可选的后续链中。不需要 orElse
或 findFirst
调用。
假设以下 类 都具有全参数构造函数和吸气剂:
class Employee {
private final long id;
private final String firstName;
private final String lastName;
}
class EmployeeDTO {
private final long id;
private final String name;
private final String surname;
}
...你可以执行此操作。除了找到一种方法从 Employee
的字段创建 EmployeeDTO
之外,别无他法。如果返回从 employeeRepository
返回的 Optional
,则不会发生映射并返回空的 Optional
。
@Override
@LogExecution
@Transactional(readOnly = true)
public Optional<EmployeeDTO> findByUuid(UUID uuid) {
return employeeRepository
.findByUuid(uuid) // Optional<Employee>
.map(emp -> new EmployeeDTO( // Optional<EmployeeDTO>
emp.getId(), // .. id -> id
emp.getFirstName(), // .. firstName -> name
emp.getLastName())); // .. lastName -> surname
}
注意:对于 Employee
-> EmployeeDTO
映射,我建议选择其中之一:
- 在
EmployeeDTO
中创建接受 Employee
的构造函数,允许与 .map(EmployeeDTO::new)
映射(缺点:创建依赖项)。
- 只需映射 getters/setters。
- 使用 MapStruct 或任何其他映射框架。
有多种方法可以将您的实体映射到 DTO。
- 使用投影:您的存储库可以通过使用投影直接return DTO。如果您根本不需要该实体,这可能是最佳选择。您可以在此处找到有关投影的所有信息 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
- 使用像 mapstruct or modelmapper 这样的库来生成您的映射代码
- 向您的 DTO 添加构造函数或静态工厂方法。像
class EmployeeDTO {
// fields here ...
public static EmployeeDTO ofEntity(Employee entity) {
var dto = new EmployeeDTO();
// set fields
return dto;
}
}
并在您的服务中调用 employee.map(EmployeeDTO::ofEntity)
。
我是 Spring 的新手,虽然我可以将域实体转换为 List<Entity>
,但我无法将它们正确转换为 Optional<Entity>
。我在存储库和服务中有以下方法:
EmployeeRepository:
@Query(value = "SELECT ...")
Optional<Employee> findByUuid(@Param(value = "uuid") final UUID uuid);
员工服务:
@Override
@LogExecution
@Transactional(readOnly = true)
public Optional<EmployeeDTO> findByUuid(UUID uuid) {
Optional<Employee> employee = employeeRepository.findByUuid(uuid);
return employee
.stream()
.map(EmployeeDTO::new)
// .orElse(null);
//.findFirst(); /// ???
}
我的问题:
1.我应该如何正确地将Optional<Employee>
转换为Optional<EmployeeDTO>
?
2.是否Spring JPA
收集SELECT
子句中的字段,并在service方法中映射到对应的DTO
匹配他们的名字?如果是这样,它是否维护命名,例如employee_name
到 employeeName
在数据库 table 和领域模型 class?
employeeRepository#findByUuid
的输出 Optional<Employee>
和方法输出类型 Optional<EmployeeDTO>
之间发生的映射是 1:1,所以这里不涉及Stream
(调用stream()
)。
您只需将 Employee
的字段正确映射到 EmployeeDTO
。处理从 employeeRepository#findByUuid
返回的 Optional
实际上为空的情况可以留在可选的后续链中。不需要 orElse
或 findFirst
调用。
假设以下 类 都具有全参数构造函数和吸气剂:
class Employee {
private final long id;
private final String firstName;
private final String lastName;
}
class EmployeeDTO {
private final long id;
private final String name;
private final String surname;
}
...你可以执行此操作。除了找到一种方法从 Employee
的字段创建 EmployeeDTO
之外,别无他法。如果返回从 employeeRepository
返回的 Optional
,则不会发生映射并返回空的 Optional
。
@Override
@LogExecution
@Transactional(readOnly = true)
public Optional<EmployeeDTO> findByUuid(UUID uuid) {
return employeeRepository
.findByUuid(uuid) // Optional<Employee>
.map(emp -> new EmployeeDTO( // Optional<EmployeeDTO>
emp.getId(), // .. id -> id
emp.getFirstName(), // .. firstName -> name
emp.getLastName())); // .. lastName -> surname
}
注意:对于 Employee
-> EmployeeDTO
映射,我建议选择其中之一:
- 在
EmployeeDTO
中创建接受Employee
的构造函数,允许与.map(EmployeeDTO::new)
映射(缺点:创建依赖项)。 - 只需映射 getters/setters。
- 使用 MapStruct 或任何其他映射框架。
有多种方法可以将您的实体映射到 DTO。
- 使用投影:您的存储库可以通过使用投影直接return DTO。如果您根本不需要该实体,这可能是最佳选择。您可以在此处找到有关投影的所有信息 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
- 使用像 mapstruct or modelmapper 这样的库来生成您的映射代码
- 向您的 DTO 添加构造函数或静态工厂方法。像
class EmployeeDTO {
// fields here ...
public static EmployeeDTO ofEntity(Employee entity) {
var dto = new EmployeeDTO();
// set fields
return dto;
}
}
并在您的服务中调用 employee.map(EmployeeDTO::ofEntity)
。