我有一个Employee(雇员表)实体类,它包含复合主键EmployeeId(名称、位置、状态)。我只需要按选定的主键(名称、位置)进行过滤。
@Entity
@Table(name = "EMPLOYEE")
class Employee {
@EmbeddedId
EmployeeId id;
@Column(name = "DESC")
String desc;
}
public class EmployeeId implements Serializable {
@Column(name = "name")
private String name;
@Column(name = "location")
private String location;
@Column(name = "status")
private String status;
}
但我不能使用以下内容,因为我没有状态值:
interface EmployeeJpaRepository extends JpaRepository<Employee, EmployeeId > {
List<Employee> findAllByIdIn(Set<EmployeeId > employeeId);
}
我可以使用这个:
interface EmployeeJpaRepository extends JpaRepository<Employee, EmployeeId > {
List<Employee> findAllByIdNameAndIdPlanLocation(String name, String location);
}
这是我每次需要查询的时候。对性能非常不利。
有什么更好的基于性能的方法吗?
还有另一种有趣的方法可以通过Spring Data Jpa规范来实现这一点。
首先使用 JpaSpecificationExecutor 扩展您的存储库
public interface EmployeeRepository
extends JpaRepository<Employee, EmployeeId>, JpaSpecificationExecutor<Employee> {}
然后,假设您在地图中拥有员工姓名和位置(任何可迭代的都可以):
Map<String, String> nameLocations = Map.of("Bob", "Nowhere", "Jules", "Here");
Specification<Employee> employeeSpec = Specification.where((root, query,
builder) -> builder.or(nameLocations.entrySet().stream()
.map(nameLocation -> builder.and(
builder.equal(root.get("id").get("name"), nameLocation.getKey()),
builder.equal(root.get("id").get("location"), nameLocation.getValue())))
.toArray(Predicate[]::new)));
List<Employees> employeesByNameAndLocation = employeeRepository.findAll(employeeSpec);
这将为您提供名为“Bob”且位置为“Nowhere”的员工和名为“Jules”且位置“Here”的员工,方法是生成以下单个查询:选择employee0_.location作为location1_0_,employee 0_.name作为name2_0_,employee0_.desc为EMPLOYEE EMPLOYEE_0_的desc4_0_,其中EMPLOYEE.0_.name=“Bob”和EMPLOYEE-0_.location=“Nowhere”或employey0_.name=“Jules”和employee0.location=“Here”
如果你不喜欢规范,你也可以使用嵌入的对象,如Srivastava建议@Pranay:
@Embeddable
@Immutable
public class PartialEmployeeId implements Serializable {
@Column(name = "name", insertable = false, updatable = false)
private String name;
@Column(name = "location", insertable = false, updatable = false)
private String location;
public PartialEmployeeId(String name, String location) {
this.name = name;
this.location = location;
}
public PartialEmployeeId() {}
}
注意可插入
和更新
标志,以防止重复的列映射。然后将其嵌入您的员工
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@EmbeddedId
EmployeeId id;
@Embedded
PartialEmployeeId partialId;
@Column(name = "DESC")
String desc;
}
,使用来自Spring data JPA的派生查询更新您的存储库:
public interface EmployeeRepository
extends JpaRepository<Employee, EmployeeId>{
List<Employee> findByPartialIdIn(List<PartialEmployeeId> partialEmployeeIds);
}
然后这样使用:
PartialEmployeeId nameAndLocation1 = new PartialEmployeeId("Bob", "Nowhere");
PartialEmployeeId nameAndLocation2 = new PartialEmployeeId("Jules", "Here");
List<Employees> employeesByNameAndLocation = employeeRepository.findByPartialIdIn(List.of(nameAndLocation1, nameAndLocation2));
这将生成与规范相同的单个SQL查询。
您可以考虑不同的方法:
1.制作两个复合主键用名称和位置制作一个复合主键。另一个包含所有属性(名称、位置和状态)。
2.为您正在使用的各个数据库供应商(MySQL、PostgreSQL等)编写自定义查询。在Repository类中调用的方法上方使用@query
Annotation。
示例:
@Query("Select e from EmployeeId where e.name like %?1% and e.location like %?1%")
List<Employee> findAllByIdNameAndIdPlanLocation(String name, String location);
我不确定他们是否会按照您的要求提高性能。但你也可以考虑它们。
更新
有关该主题的更多报道,请参阅链接。JPA Spring JPA @Embedded
和@EmbeddedId
中的复合主键