【问题标题】:Querying a view with JPA returns weird results使用 JPA 查询视图会返回奇怪的结果
【发布时间】: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 不会修改您的查询数据。您的视图查询有问题!
  • 我想得到准确的视图数据,因为我的视图数据是正确的。

标签: java 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 数据库
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 2014-12-31
  • 2023-04-02
  • 2018-09-01
  • 2012-05-30
  • 2019-12-11
  • 2012-08-08
相关资源
最近更新 更多