Получение повторяющихся записей с помощью Hibernate

Я испытываю странную проблему при использовании JPA / Hibernate. Я вижу повторяющиеся записи во время тестирования.

вот мой класс BaseEntity:

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {

    @Id
    @Column(name = "ID", updatable = false, nullable = false)
    @GenericGenerator(name = "uniqueIDGenerator", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = {
            @org.hibernate.annotations.Parameter(name = "sequence_name", value = "ID_SEQUENCE"),
            @org.hibernate.annotations.Parameter(name = "increment_size", value = "100"),
            @org.hibernate.annotations.Parameter(name = "optimizer ", value = "pooled") })
    @GeneratedValue(generator = "uniqueIDGenerator")
    @NotNull
    protected int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

}

вот мой основной партнер класс:

@Entity
@Table(name = "partner")
public class Partner extends BaseEntity{

    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy="partner", fetch=FetchType.EAGER)
    @Cascade(CascadeType.DELETE)
    private List<Receipt> receipts;

    @OneToMany(mappedBy="partner", fetch=FetchType.EAGER)
    @Cascade(CascadeType.DELETE)
    private List<Delivery> deliveries;

    public Partner() {
        setReceipts(new ArrayList<Receipt>());
        setDeliveries(new ArrayList<Delivery>());
    }

    public Partner(String name){
        this();

        this.setName(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Receipt> getReceipts() {
        return receipts;
    }

    public void setReceipts(List<Receipt> receipts) {
        this.receipts = receipts;
    }

    public List<Delivery> getDeliveries() {
        return deliveries;
    }

    public void setDeliveries(List<Delivery> deliveries) {
        this.deliveries = deliveries;
    }
}

партнер имеет два подкласса, получение и доставка. Вот класс квитанции:

@Entity
@Table(name = "receipt")
public class Receipt extends BaseEntity{

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="partnerId")
    private Partner partner;

    @Column(name = "name")
    private String name;
    @Column(name = "json")
    private String json;

    @Transient
    private ReceiptContainer receiptContainer;


    public Receipt() {
    }
    public Receipt(String name){
        this();

        this.setName(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getJson() {
        return json;
    }

    public void setJson(String json) {
        this.json = json;
    }

    public ReceiptContainer getReceiptContainer() {
        return receiptContainer;
    }

    public void setReceiptContainer(ReceiptContainer receiptContainer) {
        this.receiptContainer = receiptContainer;
    }

    public Partner getPartner() {
        return partner;
    }

    public void setPartner(Partner partner) {
        this.partner = partner;
    }

}

вот класс доставки:

@Entity
@Table(name = "delivery")
public class Delivery extends BaseEntity{

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="partnerId")
    private Partner partner;

    @Column(name = "name")
    private String name;
    @Column(name = "json")
    private String json;

    @Transient
    private DeliveryContainer deliveryContainer;


    public Delivery() {
    }
    public Delivery(String name){
        this();

        this.setName(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getJson() {
        return json;
    }

    public void setJson(String json) {
        this.json = json;
    }

    public DeliveryContainer getDeliveryContainer() {
        return deliveryContainer;
    }

    public void setDeliveryContainer(DeliveryContainer deliveryContainer) {
        this.deliveryContainer = deliveryContainer;
    }

    public Partner getPartner() {
        return partner;
    }

    public void setPartner(Partner partner) {
        this.partner = partner;
    }

}

Я получаю мои объекты вроде этого:

@Transactional
public Partner get(int id){
    Partner partner = entityManager.find(Partner.class, id);
    return partner;
}

как вы можете видеть, партнер класс включает в себя список объектов и список объектов, которые хранятся в собственных таблицах поступления и доставки соответственно.

---прежде чем я пойду дальше, я хотел бы отметить, что правильное количество записей отображается в базе данных. Эта проблема возникает только при получении объектов в моем приложении Java.---

когда я добавляю один объект и никаких объектов нет, отображается один объект и никакие объекты не отображаются, что ожидается. Если один объект и один объекты существуют, один объект и один объект отображаются, снова, что ожидается. Проблема возникает, когда присутствует более одного или объекта. Например, если добавлены два объекта, но добавлен только один объект, отображаются два объекта и два объекта.

чтобы лучше проиллюстрировать это, см. мой тест таблице ниже. Неожиданные результаты окружены тире.

<Receipt> Obj Added | <Delivery> Obj Added | <Receipt> Obj Displayed | <Delivery> Obj Displayed
         0          |          0           |           0             |            0
         0          |          1           |           0             |            1
         1          |          0           |           1             |            0
         1          |          1           |           1             |            1
         1          |          2           |        ---2---          |         ---2---
         2          |          1           |        ---2---          |         ---2---
         2          |          2           |        ---4---          |         ---4---

мой вопрос в том, почему я вижу эти неожиданные результаты?

5 ответов


причина, по которой вы видите дубликаты, заключается в том, что вы с нетерпением получаете детей, которые создают внешнее соединение.

(вы можете использовать @Fetch (FetchMode.Выберите), но это приведет к дополнительным запросам для получения ваших элементов)

ссылка Hibernate API, указывающая на внешнее соединение, имеет место.

вот подробный ответ на ваш вопрос:критерий гибернации возвращает детей несколько раз с Параметра fetchtype.Нетерпеливый!--6-->

вы можете переключиться из списка в набор (убедитесь, что вы переопределяете equals/compareTo/hashCode, если вы это сделаете). Или вы можете добавить преобразователь результатов в результаты запроса, если вы извлекаете эти элементы из базы данных с помощью критериев.

для чего это стоит, hibernate рекомендует использовать наборы над списками


возможно, вы можете попробовать выполнить запрос с помощью DISTINCT property.

просто добавьте это к своим критериям:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

Если вы не используете критерии:

SELECT DISTINCT <QUERY>

Если это не решит вашу проблему, покажите свой код запроса.


вы можете сохранить результат запроса в Set, он удалит дубликат для вас.


Если вы используете JPA:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Receipt> query = cb.createQuery(Receipt.class);
query.distinct(true);

в противном случае см. ответ Gernan по.


Hibernate не возвращает отличные результаты для запроса с включенной выборкой внешнего соединения для коллекции (даже если я использую ключевое слово distinct)? читать больше, это может помочь вам..