【发布时间】:2013-12-03 17:24:38
【问题描述】:
我有一个名为 Fee 的实体类。执行初始查询后,如果返回多个费用,我想仅在第一个查询返回的行上添加一些(WHERE)条件。既然一个码sn-p胜过千字,这里是:
// Results of initial query
List<Fee> fees = queryFindFees.getResultList();
if (fees == null || fees.size() <= 0)
return null;
if (fees.size() == 1) {
Fee f = fees.get(0);
jpa.refresh(f);
return f;
}
// More than one fee found
String sqlBase = "SELECT f FROM Fee f WHERE f IN :fees";
String sqlComplete = sqlBase/* + " AND f.isValid = ?1"*/;
queryFindFees = jpa.createQuery(sqlComplete);
queryFindFees.setParameter("fees", fees);
// Commented out for test
// queryFindFees.setParameter(1, "Y");
List<Fee> specFees = queryFindFees.getResultList();
现在,由于我实际上是要求 EntityManager 返回上一个查询中已返回的所有费用,因此我希望得到相同的结果集。相反,列表 specFees 始终为空。
我做错了什么?
提前致谢,
卢卡
编辑 1:实体类费用的详细信息
@Entity
public class Fee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private long id;
@Column(nullable = false, length = 1)
private String isValid;
...
@Override
public boolean equals(Object arg0) {
if (!(arg0 instanceof Fee))
return false;
Fee f0 = (Fee) arg0;
return f0.getId() == this.getId();
}
}
生成的 SQL(sqlComplete 变量)符合预期:
SELECT f FROM Fee f WHERE f IN :fees
编辑 2:正如 Deepak 所建议的,使用 ID 集合有效:
String sqlBase = "SELECT f FROM Fee f WHERE f.id IN :feesIds";
String sqlComplete = sqlBase/* + " AND f.isValid = ?1"*/;
List<Long> feesIds = new ArrayList<Long>();
for (Fee f : fees) {
feesIds.add(f.getId());
}
queryFindFees = jpa.createQuery(sqlComplete);
queryFindFees.setParameter("feesIds", feesIds);
使用此代码可以查询(返回所有原始费用),但如果可能,我想避免使用 for 循环,因为费用实例的数量可能非常大...
【问题讨论】:
-
我猜,in 子句应该带括号为“SELECT f FROM Fee f WHERE f IN (:fees)”;
-
@Gayathri 谢谢,但我相信这取决于 JPA 的实现和版本,在我的(EclipseLink 2.5)中,没有括号是正确的(我也尝试添加它们,但出现语法错误)。
-
确实,在某些情况下需要括号。再次感谢。
-
生成的SQL是什么?是您所期望的吗?最初返回的实体是否都将 isValid 标志设置为“Y”?
-
@luc 您使用了 createQuery,它采用 JPQL 并将其转换为 SQL。打开最精细的日志记录和参数日志记录,以查看 SQL 和参数是否与传入 ID 列表而不是实体时相同。如果您还没有发布 eclipselink 的版本并尝试最新版本 - 我似乎相信集合参数中的实体可能已经修复了这样的问题,但我不记得细节了。
标签: java jpa eclipselink jpql