簡體   English   中英

java - Hibernate merge正在生成新行而不是更新

[英]java - Hibernate merge is generating new rows instead of updating

我正在使用Hibernate-EntityManager version 4.3.5 我有多個表使用帶有生成值的id。

插入等工作正常,但是當我嘗試合並時,Hibernate不會更新舊行並創建新行。

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

合並前: 合並前

合並后: 合並后

我嘗試使用自定義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不會在局部變量中設置id。 這意味着您可以在合並時覆蓋現有的那些。 雖然,這並沒有解決我的問題。

這是我正在使用的代碼:

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

我無能為力導致這個問題。

好吧,我找到了解決方案。 非常感謝Kulbhushan Singh讓我發現了這個:

我在我的代碼中使用@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。 因此,在需要時嘗試從數據庫中提取數據,並在完成后讓垃圾收集器使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM