为 JPA 本机查询的结果分配 ID 的最简单方法是什么?
What is the simplest way to assign an ID to a result from a JPA native query?
我有一个复杂的 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 要求 Student
bean 用 @Entity
注释,这需要 @Id
。 API 还要求匹配所有字段。不幸的是,我的 select 子句来自各种来源,因此实际上并没有一个 Id。事实上,我想稍后在调用 StudentRepostiory.save(student)
.
时生成一个 id
我遇到了 22 条军规。我需要生成对象的 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
。因为这是一个实体,它要求你有一个默认的无参数构造函数,所以你也需要声明它。
所以你有 2 个构造函数,一个无参数,另一个有 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.
中看到此实现的示例
我有一个复杂的 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 要求 Student
bean 用 @Entity
注释,这需要 @Id
。 API 还要求匹配所有字段。不幸的是,我的 select 子句来自各种来源,因此实际上并没有一个 Id。事实上,我想稍后在调用 StudentRepostiory.save(student)
.
我遇到了 22 条军规。我需要生成对象的 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
。因为这是一个实体,它要求你有一个默认的无参数构造函数,所以你也需要声明它。
所以你有 2 个构造函数,一个无参数,另一个有 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.
中看到此实现的示例