Запрос представления с JPA возвращает странные результаты - PullRequest
0 голосов
/ 19 февраля 2019

это мои данные просмотра:

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,016
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 голосов
/ 19 февраля 2019

Ваша проблема в том, что столбец, который вы пометили @Id (F1), не является уникальным для вас.Ваш провайдер JPA (например, hibernate) предполагает, что значение F1 является уникальным в представлении.

Так вот, что происходит при выполнении запроса:

Допустим, что первыйвыбранная строка:

30.0 120.0 1500.0 16.

Ваш провайдер JPA связывает эту строку с идентификатором 30.0 (значением столбца F1).

Допустим, следующая выбранная строка - 30.0 120.0 4000.0 16.Теперь мы видим, что этот ряд отличается от первого.Но ваш провайдер JPA этого не знает.Поставщик видит, что id этой строки имеет значение 30.Поскольку он уже получил строку с этим идентификатором (и имеет ее в сеансе / кэше), он считает, что это та же строка.Поэтому вместо создания нового объекта для второй строки он помещает тот же объект из первой строки.

Чтобы решить эту проблему, вы должны либо создать реальный столбец id (который будет иметь уникальныйзначения в представлении) или использовать необработанные запросы SQL.

Добавление столбца ID в представление

MySQL:
Вы можете добавить уникальный идентификатор в представление, используя UUID() функция в MySQL.Это объясняется здесь .С 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.Вы можете проверить это здесь .

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...