Hibernate createNativeQuery returns 重复行
Hibernate createNativeQuery returns duplicate rows
我有 2 个数据库表 Customer 和 Items 具有 1 -> many 关系。要从数据库中获取数据,我使用以下查询。
select customer.id, customer.name, items.itemName, items.itemPrice from testdb.customer INNER JOIN items ON items.customer_Id = customer.id
我有一个实体class客户
@Entity
public class Customer{
@Id
private int id;
@Column
private String name;
@Column
private String itemName;
@Column
private int itemPrice;
public Customer() {}
//Getter and setter are here
.......
}
在服务中 class 我有以下代码。
@GET @Path("/getCustomerInfo")
@Produces(MediaType.APPLICATION_JSON)
public List getCustomerInfo() {
CustomerDao dao = new CustomerDao();
return dao.getBuildingsCustomerInfo();
}
在我的 DAO class 我有以下代码
public List<Customer> getCustomerInfo(){
Session session = SessionUtil.getSession();
String queryString = "the above mentioned query";
List<Customer> customerInfo = session.createNativeQuery(queryString, Customer.class) ;
session.close();
return customerInfo;
}
我收到来自服务的以下 JSON 响应
[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:2, name:"James", itemName:"watch", itemPrice:20 ],[id:2, name:"James", itemName:"watch", itemPrice:20 ], [id:2, name:"James", itemName:"watch", itemPrice:20 ]
结果数是5,这是正确的但是第二个结果是第一个的副本,第四个和第五个是第三个的副本。在第二、第四和第五个结果中,itemName 和 itemPrice 应该不同。
如果我使用 createSQLQuery(queryString);
而不是 createNativeQuery(queryString, Customer.class);
,我会得到正确的结果,但没有实体属性名称。
[1, "Alfred", "jeans", 10],[1, "Alfred", "shirt", 15],[2, "James", "watch", 20], [2, "James", "coffee", 25], [2, "James", "drinks", 30]
我看过很多文章,但找不到解决方案。我必须使用 createNativeQuery() 而不是 createSQLQuery() 因为我需要映射实体 class 属性。如果我做错了什么,请告诉我。
不确定重复背后的确切原因,但 SELECT DISTINCT
将解决您的问题,因为它只需要不同的记录。
参考using-distinct-in-jpa
你的数据结构在Java这边是错误的,不符合数据库关系。在您描述的关系中,您需要有一个项目列表:
@Entity
public class Customer implements Serializable {
// ... the fields you have so far
// assuming the parent field on the other side is called customer
// you may also want to set the cascade and orphanRemoval properties of the annotation
@OneToMany(mappedBy = "customer")
@JsonManagedReference // assuming you're using Jackson databind JSON
private List<Item> items;
}
在物品方面:
@Entity
public class Item implements Serializable {
@Id
private int id;
@JsonBackReference
@ManyToOne
@JoinColumn(name = "customer_Id")
private Customer customer;
}
然后,如果您真的 JSON 数据以这种方式构建,则需要第三个实体 class 用作 ResultSetMapping。
@Entity
@SqlResultSetMapping(
name = "CustomerItem",
entities = @EntityResult(entityClass = CustomerItem.class)
)
@NamedNativeQueries({
@NamedNativeQuery(
name = "CustomerItem.getAll",
resultSetMapping = "CustomerItem"
query = "select customer.id as cid, items.id as iid, customer.name,"
+ " items.itemName, items.itemPrice from testdb.customer INNER JOIN"
+ " items ON items.customer_Id = customer.id"
)
})
public class CustomerItem implements Serializable {
@Id
private int cid;
@Id
private int iid;
@Column
private String name;
@Column
private String itemName;
@Column
private int itemPrice;
... getters and setters
}
然后您可以在命名变体中使用本机查询,这应该会提供一些轻微的优化。
List<CustomerItem> lst = em.createNamedQuery("CustomerItem.getAll", CustomerItem.class)
.getResultList();
@SqlResultSetMapping
的使用是为了不监视返回的实体的变化,但您仍然可以使用定义的实体作为结果。我相信根据 JPA 规范,没有它也应该可以工作,但在 Hibernate 中却不行。可能是错误,或计划但未实现的功能,或者我可能只是误解了 JPA 的用法,但此解决方法确实适用于 Hibernate 5+。
我使用@SqlResultSetMapping 解决了这个问题
我有 2 个数据库表 Customer 和 Items 具有 1 -> many 关系。要从数据库中获取数据,我使用以下查询。
select customer.id, customer.name, items.itemName, items.itemPrice from testdb.customer INNER JOIN items ON items.customer_Id = customer.id
我有一个实体class客户
@Entity
public class Customer{
@Id
private int id;
@Column
private String name;
@Column
private String itemName;
@Column
private int itemPrice;
public Customer() {}
//Getter and setter are here
.......
}
在服务中 class 我有以下代码。
@GET @Path("/getCustomerInfo")
@Produces(MediaType.APPLICATION_JSON)
public List getCustomerInfo() {
CustomerDao dao = new CustomerDao();
return dao.getBuildingsCustomerInfo();
}
在我的 DAO class 我有以下代码
public List<Customer> getCustomerInfo(){
Session session = SessionUtil.getSession();
String queryString = "the above mentioned query";
List<Customer> customerInfo = session.createNativeQuery(queryString, Customer.class) ;
session.close();
return customerInfo;
}
我收到来自服务的以下 JSON 响应
[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:2, name:"James", itemName:"watch", itemPrice:20 ],[id:2, name:"James", itemName:"watch", itemPrice:20 ], [id:2, name:"James", itemName:"watch", itemPrice:20 ]
结果数是5,这是正确的但是第二个结果是第一个的副本,第四个和第五个是第三个的副本。在第二、第四和第五个结果中,itemName 和 itemPrice 应该不同。
如果我使用 createSQLQuery(queryString);
而不是 createNativeQuery(queryString, Customer.class);
,我会得到正确的结果,但没有实体属性名称。
[1, "Alfred", "jeans", 10],[1, "Alfred", "shirt", 15],[2, "James", "watch", 20], [2, "James", "coffee", 25], [2, "James", "drinks", 30]
我看过很多文章,但找不到解决方案。我必须使用 createNativeQuery() 而不是 createSQLQuery() 因为我需要映射实体 class 属性。如果我做错了什么,请告诉我。
不确定重复背后的确切原因,但 SELECT DISTINCT
将解决您的问题,因为它只需要不同的记录。
参考using-distinct-in-jpa
你的数据结构在Java这边是错误的,不符合数据库关系。在您描述的关系中,您需要有一个项目列表:
@Entity
public class Customer implements Serializable {
// ... the fields you have so far
// assuming the parent field on the other side is called customer
// you may also want to set the cascade and orphanRemoval properties of the annotation
@OneToMany(mappedBy = "customer")
@JsonManagedReference // assuming you're using Jackson databind JSON
private List<Item> items;
}
在物品方面:
@Entity
public class Item implements Serializable {
@Id
private int id;
@JsonBackReference
@ManyToOne
@JoinColumn(name = "customer_Id")
private Customer customer;
}
然后,如果您真的 JSON 数据以这种方式构建,则需要第三个实体 class 用作 ResultSetMapping。
@Entity
@SqlResultSetMapping(
name = "CustomerItem",
entities = @EntityResult(entityClass = CustomerItem.class)
)
@NamedNativeQueries({
@NamedNativeQuery(
name = "CustomerItem.getAll",
resultSetMapping = "CustomerItem"
query = "select customer.id as cid, items.id as iid, customer.name,"
+ " items.itemName, items.itemPrice from testdb.customer INNER JOIN"
+ " items ON items.customer_Id = customer.id"
)
})
public class CustomerItem implements Serializable {
@Id
private int cid;
@Id
private int iid;
@Column
private String name;
@Column
private String itemName;
@Column
private int itemPrice;
... getters and setters
}
然后您可以在命名变体中使用本机查询,这应该会提供一些轻微的优化。
List<CustomerItem> lst = em.createNamedQuery("CustomerItem.getAll", CustomerItem.class)
.getResultList();
@SqlResultSetMapping
的使用是为了不监视返回的实体的变化,但您仍然可以使用定义的实体作为结果。我相信根据 JPA 规范,没有它也应该可以工作,但在 Hibernate 中却不行。可能是错误,或计划但未实现的功能,或者我可能只是误解了 JPA 的用法,但此解决方法确实适用于 Hibernate 5+。
我使用@SqlResultSetMapping 解决了这个问题