使用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;
}
}
合作伙伴有两个子类,Receipt和Delivery。这是Receipt类:
@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---
我的问题是,为什么我会看到这些意想不到的结果?
答案 0 :(得分:13)
您看到重复的原因是因为您急切地抓取孩子,这正在创建外部联接。
(您可以使用@Fetch(FetchMode.SELECT),但这会导致其他查询以检索您的项目)
Hibernate API reference indicating outer join takes place.
以下是对您问题的深入回答:Hibernate Criteria returns children multiple times with FetchType.EAGER
您可以从List切换到Set(如果这样做,请确保覆盖equals / compareTo / hashCode)。或者,如果您通过条件从数据库中提取这些项目,则可以将结果转换器添加到查询结果中。
对于它的价值,hibernate建议使用列表上的集合
答案 1 :(得分:5)
也许您可以尝试使用DISTINCT属性进行查询。
只需将其添加到您的标准中:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
如果您没有使用标准:
SELECT DISTINCT <QUERY>
如果它没有解决您的问题,请显示您的查询代码。
答案 2 :(得分:0)
您可以将查询结果存储在Set
中,它会为您删除重复内容。
答案 3 :(得分:0)
如果您使用的是JPA:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Receipt> query = cb.createQuery(Receipt.class);
query.distinct(true);
另见Gernan的答案。
答案 4 :(得分:0)
对于一个为集合启用外连接提取的查询,Hibernate不会返回不同的结果(即使我使用distinct关键字)?阅读more,它可能对你有帮助..