Reputation: 524
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!
This is how I have send a entity to controller
Upvotes: 0
Views: 125
Reputation: 871
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.
Upvotes: 2
Reputation: 245
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);
}
...
}
Upvotes: 0