按Jpa Query的部分主键进行过滤



我有一个Employee (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<Employee>扩展存储库,如下所示:

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"的员工。有位置"无处"员工的名字是"朱尔斯";与位置"在这里"通过生成以下单个查询:select employee0_.location as location1_0_, employee0_.name as name2_0_, employee0_.status as status3_0_, employee0_.desc as desc4_0_ from EMPLOYEE employee0_ where employee0_.name='Bob' and employee0_.location='Nowhere' or employee0_.name='Jules' and employee0_.location='Here'

如果你不喜欢规格,你也可以使用像@Pranay Srivastava建议的嵌入对象:

@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() {}
}

注意insertableupdatable标志以防止重复的列映射。然后将其嵌入到Employee

@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@EmbeddedId
EmployeeId id;
@Embedded
PartialEmployeeId partialId;
@Column(name = "DESC")
String desc;
}

,通过使用来自Spring数据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));

生成与Specifications相同的单个SQL查询。

您可以考虑以下几种不同的方法:

1。生成2个复合主键使用名称和位置创建复合主键。另一个包含所有属性(名称、位置和状态)。

2。为你正在使用的数据库供应商(MySQL, PostgreSQL等)编写一个自定义查询。在Repository类中调用的方法上方使用@QueryAnnotation

的例子:

@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

最新更新