Hibernate - 无法更新嵌入式集

时间:2011-08-16 11:23:16

标签: java mysql hibernate spring

我无法更新实体中包含的集合。我没有收到任何错误,但是当我尝试使用一组不同的升级实体更新产品时,数据库的内容保持不变。

我有一个Product实体,其中包含一组升级实体。

@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,但是,当我在会话上调用升级方法时,它无法传播该更改到数据库。

2 个答案:

答案 0 :(得分: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进行字段注入,那么最好不要在hibernate维护的集合上设置setter。

答案 1 :(得分:0)

我认为你已经在你的案例中定义了transaction manager,如果没有,定义事务管理器然后annotate更新你的更新功能 @Transactional

此外,如果您通过openSessionInViewFilter中的web.xml设置控制会话,请在下面添加调度程序设置作为过去的一部分,这对我来说已经成功了:

<dispatcher>FORWARD</dispatcher>

也尝试使用;

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