简体   繁体   中英

Hibernate:org.hibernate.NonUniqueObjectException:

I have a 3 different Entity classes ie Pashmina , Description , Image , PashminaColour . Here Pashmina have a one-to-many relationship with Description, Image, and PashminaColour. I am trying to save all these entities at a same time but got some error there:

(org.hibernate.HibernateException) org.hibernate.HibernateException: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.nepitc.mshandloomfrabics.entity.Description#0]

I have used the following code to save

@Override
public void insert(T t) throws HibernateException {
    session = sessionFactory.openSession();
    trans = session.beginTransaction();

    try {
        session.save(t);
        trans.commit();
    } catch(HibernateException ex) {
        trans.rollback();
        throw new HibernateException(ex);
    } finally {
        session.close();   
    }
}

Note: If I save Pashmina details with only one image, description or pashmina colour it let me insert but if I save Pashmina with multiple images, pashmina colours or description shows me an error.

This is how I have implemented a controller

@RequestMapping(value = "/add-pashmina", method = RequestMethod.POST)
    public @Async ResponseEntity<String> insertPashmina(@RequestBody Pashmina pashmina) {
        if (pashmina != null) {
            try {
                pashminaService.insert(pashmina);

                pashminaId = pashmina.getPashminaId();

                for (PashminaColour pash : pashmina.getPashminaColor()) {
                    pashminaColorService.insert(new PashminaColour(pash.getColor(), new Pashmina(pashminaId)));
                }

                for (Description desc : pashmina.getDescriptions()) {
                    descriptionService.insert(new Description(desc.getPashminaDescription(), new Pashmina(pashminaId)));
                }

                return new ResponseEntity<>(HttpStatus.OK);

            } catch (HibernateException e) {
                return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
            }
        } else {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }
    }

Pashmina

public class Pashmina implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "sq_pashmina_id")
    @SequenceGenerator(name = "sq_pashmina_id", sequenceName = "sq_pashmina_id")
    @Column(name = "PASHMINA_ID", unique = true, nullable = false)
    private int pashminaId;

    @Column(name = "PASHMINA_NAME")
    private String pashminaName;

    @Column(name = "PRICE")
    private double price;

    @Column(name = "ADDED_AT", insertable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date addedAt;

    @Column(name = "CATEGORY")
    private String category;

    @Column(name = "ENABLED", insertable = false)
    private Character enabled;

    @OneToMany(mappedBy = "pashmina", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<PashminaColour> pashminaColor;

    @OneToMany(mappedBy = "pashmina", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Image> images;

    @OneToMany(mappedBy = "pashmina", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Description> descriptions;

Image

public class Image implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id

    @Column(name = "IMAGE_ID")
    private int imageId;

    @Column(name = "IMAGE_NAME")
    private String imageName;

    @JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
    @ManyToOne
    private Pashmina pashmina;

    @Column(name = "PUBLIC_ID")
    private String publicId;

PashminaColour

public class PashminaColour implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id

    @Column(name = "COLOUR_ID", insertable = false)
    private int colourId;
    @Column(name = "COLOR")
    private String color;

    @JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
    @ManyToOne
    private Pashmina pashmina;

Description

public class Description implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id

    @Column(name = "DESCRIPTION_ID")
    private int descriptionId;

    @Column(name = "PASHMINA_DESCRIPTION")
    private String pashminaDescription;

    @JoinColumn(name = "PASHMINA_ID", referencedColumnName = "PASHMINA_ID")
    @ManyToOne
    private Pashmina pashmina;

For each of the class Id is inserted using trigger in oracle database. Thanks!

Let me know if you guys don't understand me

This is how I have send a entity to controller 在此处输入图片说明

I think problem is in mismatching your entity class name that you are sending from ajax request. I see that you are sending PashminaModel entity but you are using only Pashmina in your spring POJO class. Try chaning your entity class ie. Pashmina to PashminaModel , Description to DescriptionModel , Image to ImageModel , Pashmina to PashminaModel .

Hope it works.

Assuming your Pashmina sets the relationships correctly, you should only need:

    if (pashmina != null) {
        try {
            pashminaService.insert(pashmina);

            return new ResponseEntity<>(HttpStatus.OK);

        } catch (HibernateException e) {
            return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
        }
    } else {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

I would, in any case, never use a Hibernate entity to send or receive from the client - you can never trust your client to not alter your data in ways that are harmful.

To set the relationships correctly, you need to set the relationship on both sides iff both sides have a mapping to the other side, like so:

public void addPashminaColour(PashminaColour color) {
    this.pashminaColour.add(color);
    color.setPashmina(this);
}

Alternative, with clear separation of model and entity:

    public @Async ResponseEntity<String> insertPashmina(@RequestBody PashminaModel pashminaModel) {
    if (pashmina != null) {
        try {

            PashminaModel pashmina = pashminaConverter.convert(pashminaModel);

            pashminaService.insert(pashmina);

            return new ResponseEntity<>(HttpStatus.OK);
            ...
        }
        ...
    }


public class PashminaConverter {

    public Pashmina convert(PashminaModel model) {
        Pashmina pashmina = new Pashmina();

        // copy primitive fields from model to entity

        for (ColorModel colorModel : model.getColors()) {
            pashmina.addColor(colorConverter.convert(colorModel);
        }

        // same for DescriptionModel
    }
}

public class ColorConverter {

    public PashminaColour convert(ColorModel model) {
        // copy primitive fields from model to entity
    }

}

public class Pashmina {

    ...

    public void addColor(PashminaColour color) {
        this.pashminaColour.add(color);
        color.setPashmina(this);
    }

    ...
}

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