代码之家  ›  专栏  ›  技术社区  ›  Daim

Hibernate createNativeQuery返回重复的行

  •  0
  • Daim  · 技术社区  · 7 年前

    客户 项目

    我有一个实体类客户

    @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(),因为我需要映射实体类属性。如果我做错了什么,请告诉我。

    2 回复  |  直到 7 年前
        1
  •  0
  •   coladict    7 年前

    您的数据结构在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数据,那么您需要第三个实体类来用作ResultsMapping。

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

    然后可以在named variant中使用本机查询,这应该会提供一些轻微的优化。

    List<CustomerItem> lst = em.createNamedQuery("CustomerItem.getAll", CustomerItem.class)
                                   .getResultList();
    

    使用 @SqlResultSetMapping 这样就不会监视返回的实体的更改,但您仍然可以对结果使用定义的实体。我相信,按照JPA规范,它也应该在没有它的情况下工作,但在Hibernate中却不行。可能是一个bug,或者是一个计划中的,但尚未实现的特性,或者我可能只是误解了JPA的用法,但是这个解决方法确实适用于hibernate5+。

        2
  •  0
  •   Alien    7 年前

    SELECT DISTINCT 将解决您的问题,因为它将只需要不同的记录。

    参考 using-distinct-in-jpa