2015-07-13 73 views
2

我正在使用Hibernate-EntityManager version 4.3.5。我有多個表使用帶有生成值的ID。java - Hibernate合併產生新行而不是更新

插入和這樣的工作很好,但是當我嘗試合併Hibernate不更新舊行並創建新的。

內容相同,但id正在遞增。

合併前: Before merge

合併後: After merge

我試圖用一個自定義的ID生成器來檢查ID已存在。有了這個新的策略,我得到以下錯誤:

Caused by: java.sql.SQLException: Field 'product_id' doesn't have a default value 
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1094) 
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4226) 
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4158) 
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615) 

編輯

我發現@GeneratedValues不會將IDS中的局部變量。這意味着您可以在合併時覆蓋現有的。雖然,這並沒有解決我的問題。

這裏是我使用的代碼:

@Entity(name = "calculation_storage") 
@Proxy(lazy = false) 
public class CalculationStorage { 

@Id 
private Date created; 

@OneToMany(mappedBy = "storage", fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
private List<Product> products; 

public CalculationStorage(Date created) { 
    this.created = created; 
    this.products = new LinkedList<Product>() { 
     @Override 
     public boolean add(Product product) { 
      product.setStorage(CalculationStorage.this); 
      return super.add(product); 
     } 
    }; 
} 

public CalculationStorage(Date created, List<Product> products) { 
    this.created = created; 
    this.products = products; 
} 

public CalculationStorage() { 
} 

public Date getCreated() { 
    return created; 
} 

public void setCreated(Date created) { 
    this.created = created; 
} 

/** 
* Durch das aufrufen get add Methode wird der benoetigte Fremdschluesseleintrag gesetzt 
* 
* @return Alle Produkte die registriert sind 
*/ 
public List<Product> getProducts() { 
    return products; 
} 

public void setProducts(List<Product> entities) { 
    this.products = entities; 
} 

PRODUKT:

@Entity(name = "product") 
public class Product implements Serializable { 

@Id 
@Column(name = "product_id") 
//@GeneratedValue 
@GeneratedValue(strategy=GenerationType.IDENTITY, generator="IdOrGenerated") 
@GenericGenerator(name="IdOrGenerated", 
     strategy="at.iktopia.firmenverwaltung.abendabrechnung.control.hibernate.ProductIdGenerator" 
) 
private int id; 

private double costs; 

private String name; 

private ProductType type; 

@OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
private List<CalculatorEntity> entities; 

@ManyToOne 
@JoinColumn(name = "product_fk", nullable = false) 
private CalculationStorage storage; 

public Product(String name, ProductType type, double costs) { 
    this.name = name; 
    this.type = type; 
    this.costs = costs; 
    this.entities = new LinkedList<>(); 
} 

/** 
* JPA - Konstruktor 
*/ 
public Product() { 
} 

public int getId() { 
    return id; 
} 

public void setId(int id) { 
    this.id = id; 
} 

public String getName() { 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
} 

public ProductType getType() { 
    return type; 
} 

public void setType(ProductType type) { 
    this.type = type; 
} 

public List<CalculatorEntity> getEntities() { 
    return entities; 
} 

public void setEntities(List<CalculatorEntity> entities) { 
    this.entities = entities; 
} 

public double getCosts() { 
    return costs; 
} 

public void setCosts(double costs) { 
    this.costs = costs; 
} 

public CalculationStorage getStorage() { 
    return storage; 
} 

public void setStorage(CalculationStorage calculationStorage) { 
    this.storage = calculationStorage; 
} 
} 

發電機:

public class ProductIdGenerator extends IdentityGenerator { 
@Override 
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException { 
    if (obj == null) throw new HibernateException(new NullPointerException()); 

    if ((((Product) obj).getId()) == 0) return super.generate(session, obj); 

    else return ((Product) obj).getId(); 
} 
} 

被稱爲合併對象的更新方法:

public class CalculationManager implements Manager<CalculationStorage, Date, CalculationStorageList> { 

/** 
* @see Manager#save(Object) 
*/ 
@Override 
public void save(CalculationStorage calculationStorage) { 
    Validate.notNull(calculationStorage); 

    EntityManager em = PersistenceManager.getInstance().getEntityManager(); 
    EntityTransaction transaction = em.getTransaction(); 

    transaction.begin(); 

    try { 
     em.persist(calculationStorage); 
     transaction.commit(); 
    } catch (Exception e) { 
     ErrorHandler.handleException(e, JPA_PERSIST_ERROR_MESSAGE); 
     if (transaction.isActive()) 
      transaction.rollback(); 
    } 

    em.close(); 
} 

/** 
* @see Manager#update(Object) 
*/ 
@Override 
public void update(CalculationStorage calculations) { 
    Validate.notNull(calculations); 

    EntityManager em = PersistenceManager.getInstance().getEntityManager(); 
    EntityTransaction transaction = em.getTransaction(); 

    transaction.begin(); 

    try { 
     CalculationStorage c = em.getReference(CalculationStorage.class, calculations.getCreated()); 
     c.setProducts(calculations.getProducts()); 

     em.merge(c); 

     transaction.commit(); 
    } catch (EntityNotFoundException e) { 
     if (transaction.isActive()) 
      transaction.rollback(); 
     save(calculations); 
    } catch (Exception e) { 
     ErrorHandler.handleException(e, JPA_PERSIST_ERROR_MESSAGE); 
     if (transaction.isActive()) 
      transaction.rollback(); 
    } 

    em.close(); 
} 

/** 
* @see Manager#getAll() 
*/ 
@Override 
public CalculationStorageList getAll() { 
    EntityManager em = PersistenceManager.getInstance().getEntityManager(); 

    List<CalculationStorage> calculations; 

    try { 
     calculations = em.createQuery("SELECT c FROM calculation_storage c").getResultList(); 
    } catch (Exception e) { 
     ErrorHandler.handleException(e, JPA_LOAD_ERROR_MESSAGE); 
     return null; 
    } 

    em.close(); 

    return new CalculationStorageList(calculations); 
} 

/** 
* @see Manager#remove(Object) 
*/ 
@Override 
public void remove(Date primaryKey) { 
    Validate.notNull(primaryKey); 

    EntityManager em = PersistenceManager.getInstance().getEntityManager(); 
    EntityTransaction transaction = em.getTransaction(); 

    transaction.begin(); 

    try { 
     em.remove(em.getReference(CalculationStorage.class, primaryKey)); 
     transaction.commit(); 
    } catch (Exception e) { 
     ErrorHandler.handleException(e, JPA_PERSIST_ERROR_MESSAGE); 
     if (transaction.isActive()) 
      transaction.rollback(); 
    } 

    em.close(); 
} 

/** 
* @see Manager#get(Object) 
*/ 
@Override 
public CalculationStorage get(Date primaryKey) { 
    Validate.notNull(primaryKey); 

    EntityManager em = PersistenceManager.getInstance().getEntityManager(); 

    try { 
     CalculationStorage storage = em.getReference(CalculationStorage.class, primaryKey); 
     em.close(); 
     return storage; 
    } catch (Exception e) { 
     ErrorHandler.handleException(e, JPA_LOAD_ERROR_MESSAGE); 
     return null; 
    } 
} 
} 

我無能爲力可能會導致此問題。

+1

你不需要任何自定義生成器來使merge()按記錄工作。使用標準生成器,發佈您的實體和測試案例來重現問題,以便我們明白您做錯了什麼。 –

+0

@JBNizet我加了相關的代碼。 – EXSolo

+0

@Ajan是不是這到底發生了什麼?該對象的ID將被返回,這是一個整數 – EXSolo

回答

1

好的,我找到了解決方案。由於很多Kulbhushan辛格誰使我瞭解這一點:

我用我的代碼@GeneratedValue

@Id 
@Column(name = "product_id") 
@GeneratedValue 
private int id; 

什麼我不知道的是,使用@GeneratedValue當只有數據庫條目得到ID。本地對象將具有與以前相同的ID。 (默認爲0)。在我而言這將意味着product_id在數據庫中1,2,3,...在我的對象是0

當我試圖更新我的目標,我做了以下內容:

CalculationStorage dbReference = em.getReference(CalculationStorage.class, calculations.getCreated()); 
dbReference.setProducts(localStorageObject.getProducts()); 

我基本上將數據庫中生成的ID設置回0,因爲我的本地對象中ID仍然爲0。

由於我將Id設置回0,數據庫生成新的ID。

編輯:顯然,如果你重新啓動你的應用程序,本地ID值將再次爲0。所以當你需要的時候,嘗試從數據庫中提取數據,並在完成後讓垃圾收集器擁有它。

+0

因此,如果我從數據庫設置ID,那麼不插入新行?它使用以前的ID更新現有的行?\ –

相關問題