Получение повторяющихся записей с помощью 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>
Если это не решит вашу проблему, покажите свой код запроса.
Если вы используете JPA:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Receipt> query = cb.createQuery(Receipt.class);
query.distinct(true);
в противном случае см. ответ Gernan по.
Hibernate не возвращает отличные результаты для запроса с включенной выборкой внешнего соединения для коллекции (даже если я использую ключевое слово distinct)? читать больше, это может помочь вам..