以下是我的实体结构。EmployeeKey 是 Employee 中的 EmbeddedId(复合键)。
这是我想使用 Spring-Data 实现的本机查询。
select DISTINCT(ID), NAME, DEPARTMENT from EMPLOYEE;
我正在尝试使用基于接口和基于类的 Spring 数据 JPA 投影,但这些方法似乎都不起作用。基于接口的投影给出了我无法取消代理的代理列表。AFAIK 不可能在基于类的投影的构造函数中使用DISTINCT。
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@EmbeddedId
private EmployeeKey key;
@Column(name = "NAME")
private String name;
@Column(name = "DEPARTMENT")
private String department;
@Coulmn(name = "AGE")
private Integer age;
//Getter/Setters/Constructors
}
@Embeddable
public class EmployeeKey {
@Column(name = "ID")
String id;
@Column(name = "REGNO")
String regNo;
//Getter/Setters/Constructors
}
@Repository
public interface EmployeRepository extends JpaRepository<Employee, EmployeeKey>{
@Query(value = "select distinct(emp.key.id), emp.name, emp.department from Employee emp")
List<EmployeeInterfaceProjection> findUsingInterfaceProjection();
@Query(value = "select distinct(emp.key.id) as empId, emp.name as empName, emp.department as empDepartment from Employee emp")
List<EmployeeClassProjection1> findUsingClassProjection1();
@Query(value = "select new com.path.to.EmployeeClassProjection2(emp.key, emp.name, emp.department) from Employee emp")
List<EmployeeClassProjection2> findUsingClassProjection2();
@Query(value = "select distinct(emp.key.id) as empId, emp.name as empName, emp.department as empDepartment from Employee emp")
List<Object[]> findUsingObjectProjection();
}
public interface EmployeeInterfaceProjection{
EmployeeKeyInterfaceProjection getKey();
String getName();
String getDepartment();
interface EmployeeKeyInterfaceProjection{
String getId();
}
}
public class EmployeeClassProjection1{
private String empId;
private String empName;
private String empDepartment;
//Getters/Setters, Constructors, Hashcode, Equals
}
public class EmployeeClassProjection2{
private EmployeeKey key;
private String name;
private String department;
//Getters/Setters, Constructors, Hashcode, Equals
}
每种方法面临的问题
findUsingInterfaceProjection()
这给出了一个列表,我无法取消代理以获取值。Hibernate.unproxy/initialize 也无济于事。在代理上流式传输和调用 getter 时:getKey()、getName()、getDepartment() 为每个都提供 null。
findUsingClassProjection1 ()
这给出了“找不到能够从类型 [org.springframework.data.jpa.repository.query.AbstractJpaQuery $TupleConverter$TupleBackedMap ] 转换为类型 [com.path.to.EmployeeClassProjection1]”的错误。
我知道为了解决这个问题,我需要直接在查询中使用参数化构造函数。但是这样做会禁止我在构造函数中使用DISTINCT。
findUsingClassProjection2()
这种方法实际上是获取数据而不是代理,但我需要不同的过滤。不能在查询的构造函数中使用 DISTINCT。
findUsingObjectProjection()
这工作正常,但看起来是一种非常粗糙的方法。我希望使用 JPA 预测。
这就是最终对我有用的方法。我在查询中使用了与投影中的 getter 方法名称匹配的列别名(别名 = name,如果投影具有getName())。有没有必要使用一个内部接口EmployeeKeyInterfaceProjection。
public interface EmployeeInterfaceProjection{
String getId();
String getName();
String getDepartment();
}
@Query(value = "select distinct(emp.key.id) as id, emp.name as name, emp.department as department from Employee emp")
List<EmployeeInterfaceProjection> findUsingInterfaceProjection();
基于接口的投影在AbstractJpaQuery$TupleConverter$TupleBackedMap内部工作。更早的,在不使用列别名的情况下,我为每个 getId()、getName()、getDepartment() 得到了 null。使用别名可以解决这个问题。
感谢@Ho Wai Chan 为我指明了正确的方向。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句