【问题标题】:Hibernate createNativeQuery returns duplicate rowsHibernate createNativeQuery 返回重复的行
【发布时间】:2018-11-04 22:21:14
【问题描述】:

我有 2 个数据库表 CustomerItems 有 1 -> many 关系。要从数据库中获取数据,我使用以下查询。

select customer.id, customer.name, items.itemName, items.itemPrice from testdb.customer INNER JOIN items ON items.customer_Id = customer.id

我有一个实体类客户

@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
.......
}

在服务类中我有以下代码。

@GET @Path("/getCustomerInfo")
@Produces(MediaType.APPLICATION_JSON)
public List getCustomerInfo() {
    CustomerDao dao = new CustomerDao();
    return dao.getBuildingsCustomerInfo();
}

在我的 DAO 类中,我有以下代码

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,这是正确的,但第二个结果是第 1 个的副本,第 4 个和第 5 个是第 3 个的副本。在第 2、第 4 和第 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() 因为我需要映射实体类属性。如果我做错了什么,请告诉我。

【问题讨论】:

  • 尝试选择不同的
  • @K.Nicholas 问题不在选择查询中。如果我在 MySQL 中或使用 createSQLQuery(queryString) 函数运行相同的查询,我会得到正确的结果。当我使用 createNativeQuery(queryString, Customer.class) 函数运行查询时,问题就出现了。

标签: sql json hibernate web-services hibernate-mapping


【解决方案1】:

您的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 数据,则需要第三个实体类用作 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+。

【讨论】:

  • 非常感谢您的回复。我正在尝试调整您的解决方案,但是当我部署代码时出现错误“org.hibernate.AnnotationException:使用 OneToMany 或 ManyToMany 以未映射的类为目标”。在我的 Items 类中,我有 ManyToOne JoinColumn(name = "customer_Id") private Customer customer;在我的客户类中,我有 OneToMany(mappedBy = "customer") private List items;此外,我需要在客户和项目类中都有 getter 和 setter 吗?我认为我们不需要它,因为映射类是 CustomerItems。
  • 您确实需要 getter 和 setter,是的。出现这样的错误,可能意味着您必须在某处列出实体类(可能在 persistence.xml 或 orm.xml 中),因为它不会自动检测它们。我也忘了添加 @Table 注释,但我假设你有这些。
  • 我已按照您的建议更改了所有内容,但仍然出现相同的错误。获取的结果数必须为 5。我得到了正确的结果数,但第二个结果是第 1 个的副本,而第 4 个和第 5 个是第 3 个的副本。似乎如果 2 条或更多条记录的客户 ID 相同,JPA 将处理第一条记录而不是所有其他记录。
  • 它现在可以工作了。我忘记在查询中添加项目 ID。现在我在查询中添加了项目 ID,一切正常。非常感谢您的帮助。
【解决方案2】:

不确定重复背后的确切原因,但SELECT DISTINCT 将解决您的问题,因为它只需要不同的记录。

参考using-distinct-in-jpa

【讨论】:

  • 问题不在选择查询中。如果我在 MySQL 中或使用 createSQLQuery(queryString) 函数运行相同的查询,我会得到正确的结果。当我使用 createNativeQuery(queryString, Customer.class) 函数运行查询时,问题就出现了
【解决方案3】:

我使用@SqlResultSetMapping 解决了这个问题

【讨论】:

    猜你喜欢
    • 2017-06-05
    • 2016-05-15
    • 1970-01-01
    • 2017-09-17
    • 2023-04-09
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 2013-07-17
    相关资源
    最近更新 更多