简体   繁体   English

保存父实体时,Hibernate @OneToMany关联会创建重复项

[英]Hibernate @OneToMany association creates duplicates when saving parent entity

I have an association involving a Brand (for animals) and then the animal Species for which the brand can be applied to. 我有一个涉及品牌的协会(针对动物),然后涉及可以应用该品牌的动物物种。 In our case, there is the Brand model, the Species model, and a relational model BrandSpecies. 在我们的案例中,存在品牌模型,物种模型和关系模型BrandSpecies。 The two that are relevant to my question are the Brand model and the BrandSpecies model. 与我的问题有关的两个是品牌模型和BrandSpecies模型。

The form will be sending IDs for species that may already be associated with the brand. 该表格将发送可能已经与该品牌相关联的物种的ID。 I am hoping to avoid having to loop through the set and check if the species has already been accounted for. 我希望避免循环浏览集合并检查物种是否已被考虑。

I've tried calling clear() on the set of species and adding every ID sent from the server, but the old DB records still exist once the object has been persisted. 我试过在种类集上调用clear()并添加从服务器发送的每个ID,但是一旦持久化对象,旧的DB记录仍然存在。

My Brand association: 我的品牌协会:

public class PendingBrandModel implements Serializable, Comparable<PendingBrandModel> {
    .
    .
    .
 @JsonBackReference
 @OneToMany(mappedBy="pending_brand", cascade = {CascadeType.ALL})
 private Set<PendingBrandSpeciesModel> selected_species;

    ...
}

The Brand-Species association: 品牌-物种协会:

public class PendingBrandSpeciesModel implements Serializable {
...
@JsonManagedReference
@ManyToOne()
@JoinColumn(name="pending_brand", referencedColumnName="id", nullable = false)
private PendingBrandModel pending_brand;

@JsonManagedReference
@ManyToOne()
@JoinColumn(name="species", referencedColumnName="id", nullable = false)
private BrandSpeciesModel species;
// below here are the hashCode and equals override methods...
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

/* (non-Javadoc)
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    PendingBrandSpeciesModel other = (PendingBrandSpeciesModel) obj;
    Boolean brandIDsMatch = false;
    Boolean speciesIDsMatch = false;
    if(pending_brand != null && other.getPending_brand() != null) {
        if((pending_brand.getId() != null && other.getPending_brand().getId() != null) &&
                pending_brand.getId().intValue() == other.getPending_brand().getId().intValue())
            brandIDsMatch = true;
    }
    if(species != null && other.getSpecies() != null) {
        if((species.getId() != null && other.getSpecies().getId() != null) &&
                species.getId().intValue() == other.getSpecies().getId().intValue())
            speciesIDsMatch = true;
    }
    if(brandIDsMatch && speciesIDsMatch)
        return true;
    else
        return false;
}
}

My method for populating the collection of associated species: 我填充关联物种集合的方法:

public void assignBrandSpecies(PendingBrandModel brandObj) {
        if(checkedSpeciesTypesStr != null) {
            String[] speciesList = checkedSpeciesTypesStr.split(ADDL_SEPARATOR);
            // Clear existing species
            if(brandObj.getSelected_species() != null)
                brandObj.getSelected_species().clear();
            // Add the roles the admin has chosen
            for(String speciesID : speciesList) {
                PendingBrandSpeciesModel newSpecies = new PendingBrandSpeciesModel();
                newSpecies.setPending_brand(brandObj);
                newSpecies.getSpecies().setId(Integer.parseInt(speciesID));
                if(brandObj.getSelected_species() == null)
                    brandObj.setSelected_species(new HashSet<PendingBrandSpeciesModel>());
                brandObj.getSelected_species().add(newSpecies);
            }
        }
    }

I've tried it with the .clear() code and without it, but the behavior remains the same. 我已经尝试过使用.clear()代码并且没有使用它,但是行为保持不变。 And then after it's all ran I update the brand object. 然后,在全部运行之后,我更新了品牌对象。

pendingBrandDAO.update(brandObj);

However, any pre-existing records remain in the DB and new ones get added regardless of if I'm adding a combination of Brand and Species IDs that have already been used. 但是,无论我是否要添加已使用的品牌ID和物种ID的组合,任何现有记录都将保留在数据库中,并且会添加新记录。

我解决了类似的问题,重写了hashCode()和equals()。

Your posted code is incomplete (...'s) but my quess would be that it has something to do with the hashCode/equals and the fact that your id may be null when it's first added to the collection. 您发布的代码不完整(...),但我的疑问是,它与hashCode / equals和您的ID首次添加到集合中时可能为null有关。 If the computed hashCode/equals value changes from the first time you've inserted into the collection, subsequently it won't get "found" in the collection. 如果计算的hashCode / equals值从您第一次插入集合中以来就发生了变化,那么它将不会在集合中被“发现”。 This is just a rough guess, based on the code you posted. 根据您发布的代码,这只是一个粗略的猜测。 Maybe the complete code could clarify things further. 也许完整的代码可以进一步阐明问题。

This old article (see link, below) is considered somehow "controversial" by the hibernate community, but in any case it describes some of the possible pitfalls (even if the suggested solution is not always accepted by some hibernate diehards): 这篇旧文章(请参阅下面的链接)被休眠社区以某种方式“引起争议”,但是无论如何,它描述了一些可能的陷阱(即使某些休眠的顽固派并不总是接受建议的解决方案):

Don't let hibernate steal your identity 不要让冬眠窃取您的身份

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM