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

Posted

技术标签:

【中文标题】使用 JPA 查询视图会返回奇怪的结果【英文标题】:Querying a view with JPA returns weird results 【发布时间】:2019-02-19 19:45:49 【问题描述】:

这是我的视图数据:

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;
    


【问题讨论】:

应该是 d.getF1()+" " + d.getF2() + " " + d.getF3()+" "+ d.getF4()? 我的视图中没有 F2 列。只有 4 列(F1、F3、F4 和结果)。 显示你的Duplicate声明 JPA 不会修改您的查询数据。您的视图查询有问题! 我想得到准确的视图数据,因为我的视图数据是正确的。 【参考方案1】:

您的问题是您使用 @Id (F1) 注释的列在您的视图中不是唯一的。 您的 JPA 提供程序(例如 hibernate)假定 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。

德比: 在 derby 中,您可以使用 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

【讨论】:

这是我创建视图的sql,如何添加ID列?选择 FACTORS.F1, FACTORS.F3, FACTORS.F4, COUNT() 作为 APP.FACTORS GROUP BY FACTORS.F1, FACTORS.F3, FACTORS.F4 的结果有 COUNT() > 1跨度> @user9753394 我编辑了答案并添加了选择。 错误:“UUID”未被识别为函数或过程。我在 netbeans 中使用 derby。 您使用的是什么类型的数据库?我的例子是在 MYSQL 中。我在答案的底部添加了一个 mysql 示例。 我在 netbeans 中使用 java derby 数据库

以上是关于使用 JPA 查询视图会返回奇怪的结果的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JPA 和 Hibernate 中返回所有值

Spring Data JPA 查询结果返回至自定义实体

JPA 查询未在列表中返回更新的结果

JPA 查询部分字段

查询中的 JPA 似乎没有返回任何结果

JPA 查询可以将结果作为 Java 映射返回吗?