Hibernate - невозможно обновить встроенный набор - PullRequest
1 голос
/ 16 августа 2011

Я не могу обновить содержащийся набор внутри объекта. Я не получаю никаких ошибок, но при попытке обновить продукт другим набором объектов обновления содержимое базы данных остается неизменным.

У меня есть сущность Product, которая содержит набор сущностей Upgrade.

@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 ]

5 голосов
/ 17 августа 2011

Никогда, действительно, никогда не заменяйте управляемую коллекцию Hibernate новой / другой коллекцией. Вы всегда должны использовать оригинальную коллекцию и использовать методы add и remove!

никогда не делай что-то вроде этого: 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 коллекциях.

0 голосов
/ 17 августа 2011

Я полагаю, у вас уже есть transaction manager, определенный в вашем случае, если нет, определите менеджер транзакций, а затем annotate свою функцию обновления с помощью @Transactional.

Также, если вы управляете сеансом черезopenSessionInViewFilter setup в web.xml добавьте приведенную ниже настройку диспетчера как часть - в прошлом это помогло мне:

<dispatcher>FORWARD</dispatcher>

Также попробуйте использовать;

<property name="defaultAutoCommit" value="true" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...