2014-11-05 30 views
8

Występuje dziwny problem podczas używania JPA/Hibernate. Podczas testowania widzę zduplikowane wpisy.Uzyskiwanie duplikatów wpisów przy użyciu Hibernate

Oto moja klasa 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; 
    } 

} 

Oto moje główne klasy partnerem

@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; 
    } 
} 

Partner ma dwie podklasy, odbiór i dostawę. Oto klasa Otrzymanie:

@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; 
    } 

} 

Oto klasa dostawy:

@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; 
    } 

} 

jestem coraz moje obiektów tak:

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

Jak widać, klasa partnerem zawiera Lista obiektów i Lista obiektów, które są przechowywane odpowiednio w ich własnych tabelach, odbiorze i dostawie.

--- Zanim przejdę dalej, chciałbym zauważyć, że poprawna liczba wpisów jest wyświetlana w bazie danych. Ten problem występuje tylko podczas pobierania obiektów w mojej aplikacji Java .---

Po dodaniu jednego obiektu i braku obiektów, wyświetlany jest jeden obiekt i żadne obiekty nie są wyświetlane, co jest oczekiwane. Jeśli istnieje jeden obiekt i jeden obiekt, jeden obiekt i jeden obiekt są ponownie wyświetlane, co jest oczekiwane. Problem występuje, gdy występuje więcej niż jeden obiekt lub obiekt. Na przykład, jeśli zostaną dodane dwa obiekty, ale zostanie dodany tylko jeden obiekt, wyświetlone zostaną dwa obiekty ORAZ dwa obiekty.

Aby lepiej to zilustrować, zobacz poniższą tabelę przypadków testowych. Nieoczekiwane wyniki są otoczone myślnikami.

<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--- 

Moje pytanie brzmi, dlaczego widzę te nieoczekiwane wyniki?

+0

Potrzebujesz kilku dodatkowych informacji, które pomogą Ci: pokaż, w jaki sposób generujesz identyfikator dla tych klas (opublikuj swoją klasę podstawową), pokaż, jak się utrzymujesz i odzyskaj dane – zmf

+0

Po prostu dodałem, dziękuję – user1472409

Odpowiedz

10

Powód, dla którego widzisz duplikaty, polega na tym, że z niecierpliwością ściągasz dzieci, które tworzą zewnętrzne sprzężenie.

(Można użyć funkcji @Fetch (FetchMode.WYBÓR), ale spowoduje to dodatkowych zapytań odzyskać swoje przedmioty)

Hibernate API reference indicating outer join takes place.

Oto w głębi odpowiedź na pytanie: Hibernate Criteria returns children multiple times with FetchType.EAGER

Możesz przełączyć się z listy do Set (upewnij się, w razie potrzeby zastąpić equals/compareTo/hashCode). Lub możesz dodać wynikowy transformator do wyników zapytania, jeśli wyodrębnisz te elementy z bazy danych poprzez kryteria.

Na co warto, Hibernate zaleca stosowanie zestawów na listach

+0

ktoś powinien użyć listy lub zestawu na podstawie tego, czy chce mieć semantykę listy lub zestawu, nie opierając się na tym, czy jakieś rozwiązanie utrwalania "poleca". Rozwiązanie problemu trwałości powinno być przejrzyste dla wszystkiego. –

+0

Czy jest to krytyka mojego zalecenia używania zestawów lub hibernacji? – zmf

+0

To proste stwierdzenie, dlaczego każdy programista powinien wybrać konkretny typ kolekcji - wybór rozwiązania trwałości nie powinien wchodzić w skład argumentu, a jedynie model. Jeśli ludzie uznają to za "krytykę", to zależy od nich –

6

Może możesz spróbować wykonać zapytanie za pomocą właściwości DISTINCT.

Wystarczy dodać do Twoich kryteriów:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 

Jeśli nie używasz kryteria:

SELECT DISTINCT <QUERY> 

Jeśli to nie rozwiązuje problemu, pokazać swój kod zapytania.

0

Możesz zapisać wynik zapytania w numerze Set, usunie on duplikat.

0

Jeśli używasz JPA:

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

inaczej patrz odpowiedź Gernan użytkownika.

0

Hibernate nie zwraca różnych wyników dla zapytania z włączonym zewnętrznym łączeniem pobierania dla kolekcji (nawet jeśli używam odrębnego słowa kluczowego)? przeczytaj more, może ci pomóc ..

Powiązane problemy