Hibernate - unable to update embedded set
I am unable to update the contained set within an entity. I do not get any errors, but I when I attempt to update the product with a different set of upgrade entities, the contents of the database are remaining unchanged.
I have a Product entity which contains a set of Upgrade entities.
@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,
开发者_C百科 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;
}
}
This links to the following database structure:
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;
When I change the Product.upgrades
and calling sessionFactory.getCurrentSession().update(product)
I am not seeing these changes set. I am sure I am missing something here, but can't work out what it is.
This is inside a MySQL 5 database.
I am updating the set of Upgrades like this:
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);
}
where getSelectedUprades is :
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;
}
and EditProductUpgradeDetails
is a Form Backing Object which contains a field selected
linked to a checkbox for that upgrade.
I have used debugger to check if the created Set
is different, and that the Product contains that Set
, however, when I call the upgrade method on the session it is failing to propagate that change to the database.
Never, really never replace a Hibernate Managed Collection with an new/other collection. You always must use the original collection and use the add
and remove
methods!
never do something like this: product.setUpgrade(new HashSet<Upgrade>(upgradeList));
you need to do something like
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);
}
}
If you use hibernate with field injection then it is the best not to have setter on the hibernate maintained collections.
I take it you already have transaction manager
defined in your case, if not, define the transaction manager and then annotate
your update function with
@Transactional
.
Also if you are controlling session via openSessionInViewFilter
setup in web.xml
add the dispatcher setting below as part- in the past this has done the trick for me:
<dispatcher>FORWARD</dispatcher>
Also try using;
<property name="defaultAutoCommit" value="true" />
精彩评论