Hibernate:org.hibernate.NonUniqueObjectException:

Hibernate:org.hibernate.NonUniqueObjectException:

我有 3 个不同的实体 class,即 PashminaDescriptionImagePashminaColour。这里 Pashmina 与 Description、Image 和 PashminaColour 有 one-to-many 关系。我试图同时保存所有这些实体,但出现了一些错误:

(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]

我已经用下面的代码保存了

@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();   
    }
}

注意:如果我只用一张图片、描述或羊绒颜色保存 Pashmina 细节,它允许我插入,但如果我用多张图像、pashmina 颜色或描述保存 Pashmina一个错误。

这就是我实现控制器的方式

@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);
        }
    }

羊绒

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;

图片

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;

羊绒颜色

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;

描述

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;

对于每个 class Id 都是使用 oracle 数据库中的触发器插入的。 谢谢!

如果你们不明白我的意思,请告诉我

这就是我向控制器发送实体的方式

假设您的 Pashmina 正确设置了关系,您应该只需要:

    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);
    }

在任何情况下,我都不会使用 Hibernate 实体从客户端发送或接收 - 你永远不能相信你的客户端不会以有害的方式改变你的数据。

要正确设置关系,您需要在双方都设置关系,前提是双方都有到另一方的映射,如下所示:

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

备选方案,明确分离模型和实体:

    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);
    }

    ...
}

我认为问题在于您从 ajax 请求发送的实体 class 名称不匹配。我看到您正在发送 PashminaModel 实体,但您在 spring POJO class 中仅使用 Pashmina。尝试更改您的实体 class 即。 PashminaPashminaModelDescriptionDescriptionModelImageImageModelPashminaPashminaModel

希望有用。