Ich bin ein Neuling mit JPA und Hibernate. Ich habe die zwei Entitäten, Anbieter und Produkt, die unten beschrieben werden.Detached Entity Fehler durch Cascade-Attribut
@Entity
public class Vendor extends BaseEntity
{
private static final long serialVersionUID = 267250313080292374L;
@NotNull
private String name;
@NotNull
private String city;
@OneToMany(mappedBy = "vendor", cascade = CascadeType.ALL)
private List<Product> products = new ArrayList<Product>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
@Entity
public class Product extends BaseEntity
{
private static final long serialVersionUID = -4676899182130380017L;
@NotNull
private String name;
@Column(nullable = false, precision = 10, scale = 2)
private double price;
@NotNull
private int quantity;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="VENDOR_ID", nullable = false)
private Vendor vendor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Vendor getVendor() {
return vendor;
}
public void setVendor(Vendor vendor) {
this.vendor = vendor;
}
}
ist mein Problem auf die Verwendung des Attributs nullable = false
in der @ManyToOne Annotation zusammen. Ich möchte, dass die entsprechende mit @ManyToOne annotierte Spalte nicht null ist. Allerdings, wenn ich die persitence der Entitäten mit dem folgenden Test testen:
public void testCreateEntity()
{
// create vendor1, set name and city
vendor1 = new Vendor();
vendor1.setName("MediaMarkt");
vendor1.setCity("Berlin");
vendor1 = service.createOrUpdateEntity(vendor1);
// create product1, set name, price and quantity
product1 = new Product();
product1.setName("Samsung Galaxy S7");
product1.setPrice(new Double("819.00"));
product1.setQuantity(1);
vendor1.getProducts().add(product1);
product1.setVendor(vendor1);
// create product at service
product1 = service.createOrUpdateEntity(product1);
...
}
wo die createOrUpdateEntity Methode Teil eines DAO Bean ist Object
@PersistenceContext
private EntityManager em;
public <T extends BaseEntity> T createOrUpdateEntity(T entity)
{
// as we have no id yet, it must be freshly brewed
if (entity.getId() == 0)
{
log.debug("createOrUpdateEntity::create:: {}", entity);
this.em.persist(entity);
}
// if there is an id, we must have dealt with it before
else
{
log.debug("createOrUpdateEntity::update:: {}", entity);
this.em.merge(entity);
}
this.em.flush();
return entity;
}
ich den Fehler:
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: de.brockhaus.stock.entity.Stock at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:765) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:758) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:398) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:111) at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:425) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:249) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ... 138 more
BEARBEITEN: Implementieren dieser example, die eine @ ManyToOne-Spalte verwendet, die mit nullable = false annotiert ist, habe ich festgestellt, dass mein Problem nicht damit zusammenhängt. Wie im vorherigen Serverprotokoll gezeigt, wird das Problem durch die Cascade-Klasse verursacht. Einige solutions in SO vorschlagen CascadeType.ALL von CascadeType.MERGE zu ändern. Andere ones zeigen unterschiedliche Strategien. Sogar einige ones sagen, dass nur die OneToMany-Seite der Assoziation Kaskade verwenden sollte. Ehrlich gesagt, dachte ich, dass die Verwendung von CascadeType.ALL auf beiden Seiten der Assoziation die beste Option ist. Aber es scheint, dass ich falsch lag. Obwohl, wie ich ausgeführt habe, bin ich ein Neuling bei JPA und Hibernate und verstehe die Gründe nicht.
Können Sie uns den Code der Methode createOrUpdateEntity (Object) anzeigen? –
@ArthurNoseda Ich habe es bereits hinzugefügt. – julian
Sie sollten sicherstellen, dass Sie 'merge' richtig verwenden. Es erstellt tatsächlich eine neue Instanz im PersistenceContext und gibt diese Instanz zurück, ohne das Eingabeargument zu ändern. 'persist' bewirkt, dass das übergebene Argument tatsächlich verwaltet wird. – Naros