Hibernate createNativeQuery返回重复的行

时间:2018-11-04 22:21:15

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

我有2个数据库表 Customer (客户)和 Items (商品),它们具有1->个多关系。为了从数据库中获取数据,我正在使用以下查询。

  

从testdb.customer的INNER JOIN项目上的customer.id,customer.name,item.itemName,item.itemPrice中选择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个副本。在第二,第四和第五个结果中,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(),因为我需要映射实体类属性。请让我知道我做错了什么。

2 个答案:

答案 0 :(得分:0)

不确定重复的确切原因,但是SELECT DISTINCT可以解决您的问题,因为它仅记录不同的记录。

引用using-distinct-in-jpa

答案 1 :(得分:0)

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