用JPA查询视图返回奇怪的结果

时间:2019-02-19 19:45:50

标签: java jpa

这是我的查看数据:

30.0 120.0 1500.0 16
 30.0 120.0 4000.0 16
 30.0 140.0 1500.0 16
 30.0 140.0 4000.0 16
 35.0 130.0 2750.0 18
 40.0 120.0 1500.0 16
 40.0 120.0 4000.0 16
 40.0 140.0 1500.0 16
 40.0 140.0 4000.0 16

这是我的代码:

public List<Duplicate> getData() {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("DXSorterPU");
    EntityManager entityManager = emf.createEntityManager();
    entityManager.getTransaction().begin();
    List<Duplicate> result = entityManager.createQuery("SELECT d FROM Duplicate d").getResultList();
    for (Duplicate d : result) {
        System.out.println(d.getF1()+"  " +d.getF3()+"  "+ d.getF4()+"  "+ d.getResult()) ;
    }
    entityManager.getTransaction().commit();
    entityManager.close();
    return result;
}

这是我通过上面的代码获得的数据:

30.0 120.0 1500.0 16
 30.0 120.0 1500.0 16
 30.0 120.0 1500.0 16
 30.0 120.0 1500.0 16
 35.0 130.0 2750.0 18
 40.0 120.0 1500.0 16
 40.0 120.0 1500.0 16
 40.0 120.0 1500.0 16
 40.0 120.0 1500.0 16

为什么结果不同?请帮助我。

这是我的重复班:

package dxsorter;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table(name = "DUPLICATE")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Duplicate.findAll", query = "SELECT d FROM Duplicate d")
    , @NamedQuery(name = "Duplicate.findByF1", query = "SELECT d FROM Duplicate d WHERE d.f1 = :f1")
    , @NamedQuery(name = "Duplicate.findByF3", query = "SELECT d FROM Duplicate d WHERE d.f3 = :f3")
    , @NamedQuery(name = "Duplicate.findByF4", query = "SELECT d FROM Duplicate d WHERE d.f4 = :f4")
    , @NamedQuery(name = "Duplicate.findByResult", query = "SELECT d FROM Duplicate d WHERE d.result = :result")})
public class Duplicate implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Basic(optional = false)
    @Column(name = "F1")
    @Id
    private BigDecimal f1;
    @Basic(optional = false)
    @Column(name = "F3")
    private BigDecimal f3;
    @Basic(optional = false)
    @Column(name = "F4")
    private BigDecimal f4;
    @Basic(optional = false)
    @Column(name = "RESULT")
    private int result;

    public Duplicate() {
    }

    public BigDecimal getF1() {
        return f1;
    }

    public void setF1(BigDecimal f1) {
        this.f1 = f1;
    }

    public BigDecimal getF3() {
        return f3;
    }

    public void setF3(BigDecimal f3) {
        this.f3 = f3;
    }

    public BigDecimal getF4() {
        return f4;
    }

    public void setF4(BigDecimal f4) {
        this.f4 = f4;
    }

    public int getResult() {
        return result;
    }

    public void setResult(int result) {
        this.result = result;
    }

    public List<Duplicate> getData() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("DXSorterPU");
        EntityManager entityManager = emf.createEntityManager();
        entityManager.getTransaction().begin();
        List<Duplicate> result = entityManager.createQuery("SELECT d FROM Duplicate d").getResultList();
        for (Duplicate d : result) {
            System.out.println(d.getF1()+"  " +d.getF3()+"  "+ d.getF4()+"  "+ d.getResult()) ;
        }
        entityManager.getTransaction().commit();
        entityManager.close();
        return result;
    }

}

1 个答案:

答案 0 :(得分:2)

您的问题是,用@Id(F1)注释的列在视图中不是唯一的。 您的JPA提供程序(例如,休眠)假定F1的值在视图中是唯一的。

这就是执行查询时发生的事情:

让我们说,获取的第一行是

30.0 120.0 1500.0 16

您的JPA提供程序将此行与ID 30.0(F1列的值)相关联。

可以说,提取的下一行是30.0 120.0 4000.0 16。现在,我们可以看到该行与第一行不同。但是您的JPA提供者不知道这一点。提供程序看到的是此行的id的值为30。因为他已经获取了具有该ID的行(并将其存储在会话/缓存中),所以他认为该行是同一行。因此,他没有在第二行中创建新对象,而是在第一行中放置了相同的对象。

为了解决此问题,您应该创建一个真实的id列(在视图中将具有唯一值)或使用原始SQL查询。

向视图添加ID列

MySQL:
您可以使用mysql中的UUID()函数向视图添加唯一标识符。 here对此进行了说明。 使用UUID,您的选择应如下所示:

SELECT UUID() as ID, FACTORS.F1, FACTORS.F3, FACTORS.F4, COUNT() AS RESULT FROM APP.FACTORS GROUP BY FACTORS.F1, FACTORS.F3, FACTORS.F4 HAVING COUNT() > 1

我在rextester上创建了一个简单的例子。您可以检出here

德比:
在德比中,您可以使用ROW_NUMBER()函数。 您的选择应如下所示:

SELECT ROW_NUMBER() OVER () as ID, FACTORS.F1, FACTORS.F3, FACTORS.F4, COUNT() AS RESULT FROM APP.FACTORS GROUP BY FACTORS.F1, FACTORS.F3, FACTORS.F4 HAVING COUNT() > 1