我有一个复杂的SQL查询,我将其作为JPA中的本机查询实现。实体管理器自动将结果集的每一行转换为Person
对象,从而产生List<Person>
String sql = "select name, address, date_of_birth from ...";
Query q = entityManager.createNativeQuery(sql, Student.class);
List<Student> results = q.getResultList();
return results;
entityManager要求用@Entity
注释Student
bean,这需要一个@Id
。API还要求所有字段都匹配。不幸的是,我的select子句从各种来源提取,因此没有真正的Id。事实上,我希望以后在调用StudentRepostiory.save(student)
时生成一个id。
我进退两难。我需要生成对象的id,但我还没有id。
我该怎么办?
- 我已经尝试使ID为空。它使所有结果为空。
- 我试过让ID为零。它使所有结果相同。
- 我已经尝试添加一个生成策略注释。什么都没做
供参考
Student.java
@Entity // This forces me to have an Id.
class Student {
@Id Long id // I'm forced to include this, but my query doesn't have one
String name;
String dateOfBirth;
String address;
// Getters and Setters
}
您可以使用@SqlResultSetMapping
和@ConstructorResult
将本机sql查询的结果映射到POJO/bean,而不需要它具有id。
注意:@ConstructorResult仅在JPA 2.1中可用。
首先,你需要在你的Student
实体中有一个构造函数,它接受3个参数:name
, dateOfBirth
和address
。因为这是一个实体,它要求你有一个默认的无参数构造函数,所以你也需要声明它。所以你有两个构造函数,一个没有参数,另一个有3个参数。
现在使用@ConstructorResult:
声明SqlResultSetMapping@SqlResultSetMapping(name="StudentMapping",
classes={
@ConstructorResult(targetClass=Student.class,
columns={
@ColumnResult(name="name", type=String.class),
@ColumnResult(name="address", type=String.class),
@ColumnResult(name="date_of_birth", type=String.class)
})
}
)
@Entity
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String String name;
private String address;
private String dateOfBirth;
public Student () {}
public Student(String name, String address, String dateOfBirth) {
this.name = name;
this.address = address;
this.dateOfBirth = dateOfBirth;
}
// Setters and Getters
}
现在,当您调用createNativeQuery
时,您可以将SQL字符串与您声明的映射名称一起传递。
String sql = "select name, address, date_of_birth from ...";
Query q = entityManager.createNativeQuery(sql, "StudentMapping");
List results = q.getResultList();
然后,稍后您可以迭代列表中的Student
对象并持久化它们。由于Student
是一个实体,并且列表中的对象还没有id字段的值,因此对这些对象调用persist将有效。
你可以在我的github repo中看到这个实现的示例