简体   繁体   中英

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. The two that are relevant to my question are the Brand model and the BrandSpecies model.

The form will be sending IDs for species that may already be associated with the brand. 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.

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

我解决了类似的问题,重写了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. 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. 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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