2011-08-16 79 views
1

我無法更新實體中包含的集。我沒有收到任何錯誤,但是當我嘗試使用不同的升級實體更新產品時,數據庫的內容保持不變。休眠 - 無法更新嵌入集

我有一個包含一組升級實體的產品實體。

@Entity 
@Table(name="product") 
public class Product { 
    private Long id; 
    private Set<Upgrade> upgrades; 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="id") 
    public Long getId() { 
     return id; 
    } 

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

    @ManyToMany(mappedBy = "products", 
       targetEntity = Upgrade.class, 
       cascade = CascadeType.ALL, 
       fetch = FetchType.EAGER) 
    public Set<Upgrade> getUpgrades() { 
     return upgrades; 
    } 

    public void setUpgrades(Set<Upgrade> upgrades) { 
     this.upgrades = upgrades; 
    } 
} 

@Entity 
@Table(name="upgrade") 
public class Upgrade { 
    private Long id; 
    private Set<Product> products; 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name="id") 
    public Long getId() { 
     return id; 
    } 

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

    @ManyToMany(targetEntity = Product.class, 
       cascade = CascadeType.ALL, 
       fetch = FetchType.EAGER) 
    @JoinTable(name = "upgrade_product", 
       joinColumns = @JoinColumn(name = "upgrade_id"), 
       inverseJoinColumns = @JoinColumn(name="product_id")) 
    public Set<Product> getProducts() { 
     return products; 
    } 

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

此鏈接到以下數據庫結構:

CREATE TABLE `product` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1; 

CREATE TABLE `upgrade` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=778 DEFAULT CHARSET=latin1; 

CREATE TABLE `upgrade_product` (
    `upgrade_id` bigint(20) NOT NULL, 
    `product_id` bigint(20) NOT NULL, 
    PRIMARY KEY (`upgrade_id`,`product_id`), 
    KEY `FK169831CC92B40B3C` (`upgrade_id`), 
    KEY `FK169831CC6DAEB65C` (`product_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

當我改變Product.upgrades並呼籲sessionFactory.getCurrentSession().update(product)我沒有看到這些更改設置。我相信我在這裏錯過了一些東西,但無法弄清楚它是什麼。

這是在MySQL 5數據庫中。

我更新了一套升級的是這樣的:

List<Upgrade> upgradeList = getSelectedUpgrades(editProduct.getAllUpgrades()); 
    if (compareUpgradeLists(new ArrayList<Upgrade>(product.getUpgrade()), upgradeList) == false) { 
     product.setUpgrade(new HashSet<Upgrade>(upgradeList)); 
     isDirty = true; 
    } 

    if (isDirty) { 
     productDao.update(product); 
    } 

其中getSelectedUprades是:

private List<Upgrade> getSelectedUpgrades (List<EditProductUpgradeDetails> list) { 
     List<Upgrade> upgradeList = new ArrayList<Upgrade>(); 
     // Update the upgrades for this product 
     for (EditProductUpgradeDetails upgradeDetails : list) { 
      if (upgradeDetails.getSelected()) { 
       // Add upgrade to new upgrade list 
       Upgrade upgrade = upgradeDao.get(upgradeDetails.getId()); 
       upgradeList.add(upgrade); 
      } 
     } 
     return upgradeList; 
    } 

EditProductUpgradeDetails是一個表單支持對象,其含有與該複選框場selected升級。

我已經使用調試器檢查創建的Set是否不同,並且產品包含Set,但是,當我在會話上調用升級方法時,它無法將該更改傳播到數據庫。

+0

究竟發生了什麼,以及如何更改集合 - 請張貼代碼片段。 – Ralph

+0

添加了更多關於正在發生的事情的詳細信息。 – Xetius

回答

5

永遠不會,真的永遠不會用新的/其他集合替換Hibernate託管集合。您始終必須使用原始集合並使用addremove方法!

永遠不會做這樣的事情:product.setUpgrade(new HashSet<Upgrade>(upgradeList));

你需要做的是這樣

class Product { 
    ... 
    private Set<Upgrade> upgrades; 
    ... 


    public void replaceUpgrades(Set<Upgrade> newUpgrades) { 
    this.upgrades.retainAll(newUpgrades); 

    HashSet<T> reallyNew = new HashSet<T>(newUpgrades); 
    reallyNew.removeAll(this.upgrades); 

    this.upgrades.addAll(reallyNew); 
    } 

}

如果您使用的字段注入冬眠那麼它是最好不要有二傳手在hibernate上維護集合。

0

我想你已經在你的情況下定義transaction manager,如果不能,請定義事務管理器,然後用annotate @Transactional您的更新功能。

此外,如果你是通過openSessionInViewFilter設置在web.xml控制會話中添加調度下方設置爲兼職在過去,這做的伎倆對我來說:

<dispatcher>FORWARD</dispatcher> 

同時嘗試使用;

<property name="defaultAutoCommit" value="true" />