开发者

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" />
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜