从JPA本机查询为结果分配ID的最简单方法是什么?

时间:2015-10-20 16:58:20

标签: java sql hibernate jpa hibernate-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设为null。它使所有结果都为空。
  • 我尝试过将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

}

1 个答案:

答案 0 :(得分:2)

您可以使用@SqlResultSetMapping@ConstructorResult将本机sql查询的结果映射到POJO / bean,而不要求它具有id。

注意:@ConstructorResult仅适用于JPA 2.1。

首先,您需要在Student实体中拥有一个带有3个参数的构造函数:namedateOfBirthaddress。由于这是一个实体,它需要你有一个默认的无参数构造函数,所以你也需要声明它。 所以你有2个构造函数,一个没有arg,另一个有3个args。

现在使用@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中看到此实现的示例。