java - Hibernate:来自本机查询的 BigInteger vs Long 用于 JPQL 查询
问题描述
在我们的 Java EE EJB 应用程序中,我们有一个类的以下 JPA/Hibernate 映射:
@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;
}
这些是与之相关的类:
@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 列表:
List<Long> seqTs = (List<Long>)em.createNativeQuery("select SEQ_T from T").getResultList();
em
的实例在哪里EntityManager
。该查询显然不是那么简单,而是非常复杂,因为它源自一些JOIN
和其他表的子查询。如果返回的列表不为空,则作业可以完成其工作,并执行此 JPQL 以加载其操作的实体:
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()
好吧,问题是调用时会引发此异常:
线程“main”java.lang.IllegalArgumentException 中的异常:参数值元素 [1] 与预期类型不匹配 [java.lang.Long (n/a)]
在这里阅读了许多帖子,并在 Eclipse 中设置了一个断点,我发现不是List<Long>
从本机查询返回 a 而是 a List<BigInteger>
(根据数据库中 PK 的本机类型),没有任何ClassCastException
或类似的。为什么这个?所以,我想我之前应该执行这样的操作:
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 了。然后将此实体传递给 DRools,并在应用规则后,此作业用于EntityManager
持久化数据。这就是为什么我需要加载 JPA 实体,否则我会得到一个
引起:org.hibernate.PersistentObjectException:分离的实体传递给持久化
或者我将不得不 .find()
再次调用 DRools 修改的每个事实,并通过调用其他对象的 getter 来设置其属性。这仍然会导致 N+1 个查询。
解决方案
更安全的方法是使用Number
而不是BigInteger
List<Long> seqTLong = new ArrayList<Long>();
for(Number seqNative : seqTs) {
seqTLong.add(seqNative.longValue());
}
推荐阅读
- lisp - 如何使用参数迭代函数,参数是 lisp 中的文件名?
- python - 句子相似性错误的通用句子编码
- python - 使用自制软件更新 python3 时,我收到一条错误消息“未安装 python3”
- python - 调用 WebSocket.close 时现有等待会发生什么
- python - PyCharm 中 Python 网络爬虫的问题。(初学者)
- spring-boot - Zuul 代理在 Tomcat vai SpringBootServlet 上不起作用
- javascript - 仅当输入有数据时才启用提交按钮
- python - 为几个连续列上的相同值设置熊猫数据框的子集
- react-native - 类到函数组件
- listview - 是什么导致鼠标指针不与组合框或列表视图上的选择对齐