【问题标题】:Hibernate:org.hibernate.NonUniqueObjectException:休眠:org.hibernate.NonUniqueObjectException:
【发布时间】:2018-12-07 04:07:29
【问题描述】:

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

(org.hibernate.HibernateException) org.hibernate.HibernateException: org.hibernate.NonUniqueObjectException: 具有相同标识符值的不同对象已与会话关联:[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,羊绒颜色或描述会显示错误。 p>

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

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

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;

说明

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;

对于Id 中的每一个类,都使用触发器在 oracle 数据库中插入。 谢谢!

如果你们不理解我,请告诉我

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

【问题讨论】:

标签: java hibernate spring-mvc hibernate-mapping


【解决方案1】:

假设您的 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);
    }

    ...
}

【讨论】:

  • 它只保存 pashmina 而不是其他的。我可能有人际关系问题。请看看我上面定义的关系,你能详细告诉我如何设置这些实体之间的关系
  • @Requestbody Pashmina 中的子实体是如何设置的?这可能是问题所在,映射本身似乎没问题(但是我会将 List 更改为 Set)。
  • 我添加了一张图片,请看上方
  • 我会更改您的控制器,以便您不直接发送实体 Pashmina,而是发送 POJO PashminaModel。将该模型发送到您的后端后,将其转换为实体 Pashmina 并添加上面的颜色和描述。这有两个优点,(a)您的应用程序不信任客户端(它不应该这样做),以及(b)您的 insert() 方法将正常工作。
  • 对不起,我没听明白,请您更正我上面的代码并发布
【解决方案2】:

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

希望它有效。

【讨论】:

    猜你喜欢
    • 2017-06-13
    • 1970-01-01
    • 2011-09-25
    • 2011-12-16
    • 2010-11-07
    • 1970-01-01
    • 2011-04-06
    • 2021-10-21
    相关资源
    最近更新 更多