Hibernate:org.hibernate.NonUniqueObjectException:
Hibernate:org.hibernate.NonUniqueObjectException:
我有 3 个不同的实体 class,即 Pashmina
、Description
、Image
、PashminaColour
。这里 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 即。 Pashmina
到 PashminaModel
、Description
到 DescriptionModel
、Image
到 ImageModel
、Pashmina
到 PashminaModel
。
希望有用。
我有 3 个不同的实体 class,即 Pashmina
、Description
、Image
、PashminaColour
。这里 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 即。 Pashmina
到 PashminaModel
、Description
到 DescriptionModel
、Image
到 ImageModel
、Pashmina
到 PashminaModel
。
希望有用。