Java JPA Hibernate SqlResultSetMapping 别名
Java JPA Hibernate SqlResultSetMapping Aliases
在使用 JPA 2.1 和 Hibernate 4.3.11 实现的 Java 应用程序中,我尝试使用 SqlResultSetMapping
将本机查询结果映射到实体。查询包括连接两个具有相同列名的表,因此我需要使用别名并映射它们(此处描述的问题:http://www.tinesoft.com/java/be-aware-of-mutliple-result-mappings-in-jpa)
为了简单起见,我将查询和实体缩小到最小,这仍然会导致问题。真正的代码使用了两个实体和数据库函数,这就是使用原生查询而不是 JPQL 的原因。
网关实体:
@Entity
public class Gateway implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer active;
...
@Column(name = "activation_code")
private String activationCode;
...
}
SqlResultSetMapping:
@SqlResultSetMapping(
name = "GatewayWithLoc",
entities = {
@EntityResult( entityClass = Gateway.class , fields = @FieldResult(name = "id", column = "gw_id"))
}
)
查询:
Query query = em.createNativeQuery("SELECT gw.id AS gw_id, ..., active, activation_code, ... FROM gateway gw", "GatewayWithLoc");
List<Object[]> rows = query.getResultList();
异常:
Caused by: org.postgresql.util.PSQLException: The column name activati2_1_0_ was not found in this ResultSet.
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.findColumn(AbstractJdbc2ResultSet.java:2803)
...
如果我在 SqlResultSetMapping
中使用没有 fields = @FieldResult...
的 SELECT *
,代码会按预期工作,但我不能这样做,因为不同表中的列名相同。
我将通过手动将结果映射到实体来解决此问题,因为我需要快速解决方案,但如果知道我做错了什么或 Hibernate 不支持我正在尝试做的事情,那就太好了。书 "Pro JPA 2" 包含非常相似的示例,应该有效。
更新:使用 Hibernate 5.1.1 (Spring 4.3.2) 测试 - 结果相同
更新:看起来像多个答案中提到的所有列名都需要指定。对我来说,这似乎是 JPA/Hibernate 的一个大问题——这些列名可以从实体派生,只有手动指定的例外。相反,我需要写 3 次列名(1. 查询,2. 结果集映射 3. 实体),这很难看且难以维护。
看起来本机查询没有映射到 SqlResultSetMapping
。查询中的列比映射中的列多得多。您查询中的选定列必须与您的映射相匹配。
您可以使用 SELECT NEW
:
创建一个 class 具有查询中需要使用的所有列。
package dz.immo;
public class GatewayGatewayWithLoc {
private Integer idGw;
private Integer activeGw;
private Integer idGwWl;
private Integer activeGwWl;
public GatewayGatewayWithLoc(Integer idGw, Integer activeGw, Integer idGwWl, Integer activeGwWl) {
this.idGw = idGw;
this.activeGw = activeGw;
this.idGwWl = idGwWl;
this.activeGwWl = activeGwWl;
}
....
// getter and setter
......
}
使用查询
Query query = em.createQuery("SELECT NEW dz.immo.GatewayGatewayWithLoc(gw.id, gw.active, gwwl.id, gwwl.active) FROM Gateway gw ,GatewayGatewayWithLoc gwwl WHERE ...");
List<GatewayGatewayWithLoc> liste = query.getResultList();
// display the answer
for (GatewayGatewayWithLoc gwgw : liste) {
System.out.println("GatewayGatewayWithLoc : " + gwgw.getIdGw() + " " + gwgw.getActiveGw()+ " " + gwgw.getIdGwWl()+ " " + gwgw.getActiveGwWl());
}`
我认为您需要明确指定所有 @FieldResult
,尤其是因为您的列名在两个表之间存在冲突。
在使用 JPA 2.1 和 Hibernate 4.3.11 实现的 Java 应用程序中,我尝试使用 SqlResultSetMapping
将本机查询结果映射到实体。查询包括连接两个具有相同列名的表,因此我需要使用别名并映射它们(此处描述的问题:http://www.tinesoft.com/java/be-aware-of-mutliple-result-mappings-in-jpa)
为了简单起见,我将查询和实体缩小到最小,这仍然会导致问题。真正的代码使用了两个实体和数据库函数,这就是使用原生查询而不是 JPQL 的原因。
网关实体:
@Entity
public class Gateway implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer active;
...
@Column(name = "activation_code")
private String activationCode;
...
}
SqlResultSetMapping:
@SqlResultSetMapping(
name = "GatewayWithLoc",
entities = {
@EntityResult( entityClass = Gateway.class , fields = @FieldResult(name = "id", column = "gw_id"))
}
)
查询:
Query query = em.createNativeQuery("SELECT gw.id AS gw_id, ..., active, activation_code, ... FROM gateway gw", "GatewayWithLoc");
List<Object[]> rows = query.getResultList();
异常:
Caused by: org.postgresql.util.PSQLException: The column name activati2_1_0_ was not found in this ResultSet.
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.findColumn(AbstractJdbc2ResultSet.java:2803)
...
如果我在 SqlResultSetMapping
中使用没有 fields = @FieldResult...
的 SELECT *
,代码会按预期工作,但我不能这样做,因为不同表中的列名相同。
我将通过手动将结果映射到实体来解决此问题,因为我需要快速解决方案,但如果知道我做错了什么或 Hibernate 不支持我正在尝试做的事情,那就太好了。书 "Pro JPA 2" 包含非常相似的示例,应该有效。
更新:使用 Hibernate 5.1.1 (Spring 4.3.2) 测试 - 结果相同
更新:看起来像多个答案中提到的所有列名都需要指定。对我来说,这似乎是 JPA/Hibernate 的一个大问题——这些列名可以从实体派生,只有手动指定的例外。相反,我需要写 3 次列名(1. 查询,2. 结果集映射 3. 实体),这很难看且难以维护。
看起来本机查询没有映射到 SqlResultSetMapping
。查询中的列比映射中的列多得多。您查询中的选定列必须与您的映射相匹配。
您可以使用 SELECT NEW
:
创建一个 class 具有查询中需要使用的所有列。
package dz.immo; public class GatewayGatewayWithLoc { private Integer idGw; private Integer activeGw; private Integer idGwWl; private Integer activeGwWl; public GatewayGatewayWithLoc(Integer idGw, Integer activeGw, Integer idGwWl, Integer activeGwWl) { this.idGw = idGw; this.activeGw = activeGw; this.idGwWl = idGwWl; this.activeGwWl = activeGwWl; } .... // getter and setter ...... }
使用查询
Query query = em.createQuery("SELECT NEW dz.immo.GatewayGatewayWithLoc(gw.id, gw.active, gwwl.id, gwwl.active) FROM Gateway gw ,GatewayGatewayWithLoc gwwl WHERE ..."); List<GatewayGatewayWithLoc> liste = query.getResultList(); // display the answer for (GatewayGatewayWithLoc gwgw : liste) { System.out.println("GatewayGatewayWithLoc : " + gwgw.getIdGw() + " " + gwgw.getActiveGw()+ " " + gwgw.getIdGwWl()+ " " + gwgw.getActiveGwWl()); }`
我认为您需要明确指定所有 @FieldResult
,尤其是因为您的列名在两个表之间存在冲突。