关于java:Hibernate:BigInteger vs Long来自本机查询,可在JPQL查询中使用

Hibernate: BigInteger vs Long from native query to be used in JPQL query

在我们的Java EE EJB应用程序中,我们具有类的以下JPA / Hibernate映射:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Entity
@Table(name="T")
@TableGenerator( /* all annotation attributes */)
public class T {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name="SEQ_T", nullable = false)
    private long seqT;

    @OneToMany(
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        mappedBy ="t",
        fetch = FetchType.LAZY
    )
    private List<W> wu;

}

和以下是与之相关的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Entity
@Table(name="W")
@TableGenerator( /* all annotation attributes */)
public class W {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name="SEQ_W", nullable = false)
    private long seqW;

    @Column(name="SEQ_T", nullable = false)
    private long seqT;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name ="SEQ_T", insertable = false, updatable = false)
    private T t;

    @OneToMany(
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        mappedBy ="w",
        fetch = FetchType.LAZY
    )
    private List<WA> wua;
 }

@Entity
@Table(name="WA")
@TableGenerator( /* all annotation attributes */)
public class WA {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name="SEQ_W_A", nullable = false)
    private long seqWA;

    @Column(name="SEQ_W", nullable = false)
    private long seqW;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name ="SEQ_W", insertable = false, updatable = false)
    private W w;

}

此外,我们有一个调度的作业,该作业由TimerService EJB定期执行。
首先,此作业必须了解是否有要执行的内容,因此它会执行以下类似的本机sql查询,以根据多种条件从T表中恢复pk列表:

1
List<Long> seqTs = (List<Long>)em.createNativeQuery("select SEQ_T from T").getResultList();

其中emEntityManager的实例。该查询显然不是那么简单,但是却非常复杂,因为它源自某些JOIN和其他表的子查询。
如果返回的列表不为空,则该作业可以完成其工作,并执行此JPQL来加载其操纵的实体:

1
2
3
4
String queryJPQL ="select wu from W wu JOIN FECTCH wu.wua where wu.seqT in :seqTs";
List<Workup> wus = em.createQuery(queryJPQL, W.class)
                     .setParameter("seqTs", seqTs)
                     .getResultList();

之所以执行此查询,是因为即使我们始终需要@OneToMany关系中的数据,如果我们将该关系设置为EAGER,也会执行N 1个查询。取而代之的是,使用JOIN FETCH执行唯一查询以恢复某种视图,然后由Hibernate关联实体和关系。

好吧,问题在于调用.setParameter()时会引发此异常:

Exception in thread"main" java.lang.IllegalArgumentException: Parameter value element [1] did not match expected type [java.lang.Long (n/a)]

在这里阅读许多文章,并在Eclipse中设置断点,我发现从本机查询返回的不是List<Long>,而是一个List<BigInteger>(根据数据库中PK的本机类型),而没有任何ClassCastException或类似。为什么这个?
因此,我想我应该在执行以下操作之前:

1
2
3
List<Long> seqTLong = new ArrayList<Long>();
for(BigInteger seqNative : seqTs)
        seqTLong.add(seqNative.longValue());

,并将其传递给查询。
无论如何,这是正确的解决方案吗?安全吗?这是因为我们的应用程序支持3 DB,并且相应地由ANT在3个JAR中构建:Oracle,PostgreSQL和SQL Server。
我可以假设每个数据库的PK值始终为BigInteger吗?在Oracle中,我们使用Number(19),在PostgreSQL中,我们使用BigInt ...我不记得SQL Server了。
然后将此实体传递给DRool,并在应用规则后,此作业使用EntityManager保留数据。这就是为什么我需要加载JPA实体的原因,否则我会得到一个

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist

否则我将不得不为DRools修改的每个事实再次调用.find(),并通过从其他对象中调用getter来设置其属性。仍然会导致N 1个查询。


一种更安全的方法是使用Number而不是BigInteger

1
2
3
4
List<Long> seqTLong = new ArrayList<Long>();
for(Number seqNative : seqTs) {
        seqTLong.add(seqNative.longValue());
}