вставить/обновить объект, который имеет отношения «многие ко многим» с другим объектом, используя API критериев Java

как говорится в вопросе. У меня есть две таблицы Products и categories.
Таблица продуктов

...
create table products (
  id int primary key generated always as identity(start with 100, increment by 1),
  name varchar(30),
  quantity int,
  unit_cost decimal not null,
  brand_name varchar(30)
)
...  

Таблица категорий

...
create table categories
(
  name varchar(30) primary key,
  description varchar(30),
  date_created date,
)

... отношения, которые у них есть, - это отношения многие ко многим, поэтому я создал таблицу отношений.

Таблица отношений

...
create table product_categories
(
  product_id int not null,
  category_name varchar(30) not null
)
alter table product_categories add constraint product_categoriesFK foreign key (product_id)
references products (id)
alter table product_categories add constraint category_productsFK foreign key (category_name)
references categories (name)  

Это соответствующий класс сущностей.

Сущность продукта

@Entity
@Table(name = "PRODUCTS")
public class Product implements Serializable {
     private static final long serialVersionUID = 1L;
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     @Basic(optional = false)
     @Column(name = "ID")
     private Integer id;
     @Size(max = 255)
     @Column(name = "NAME")
     private String name;
     @Column(name = "QUANTITY")
     private Integer quantity;
     @Column(name = "UNIT_COST")
     private Integer unitCost;
     @JoinTable(name = "REQUISITION_PRODUCTS", joinColumns = {
          @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "ID")}, inverseJoinColumns = {
     @JoinColumn(name = "REQUISITION_ID", referencedColumnName = "ID")})
     @ManyToMany
     private Collection<Requisition> requisitionCollection;
     @ManyToMany(mappedBy = "productCollection", cascade = CascadeType.ALL)
     private Collection<Category> categoryCollection;
     @JoinColumn(name = "BRAND_NAME", referencedColumnName = "NAME")
     @ManyToOne
     private Brand brand;
     @JoinColumn(name = "DEAL_ID", referencedColumnName = "ID")
     @ManyToOne
     private Deal dealId;
     @OneToMany(mappedBy = "product")
     private Collection<Feature> featureCollection;
     ...

Категория объекта

@Entity
@Table(name = "CATEGORIES")
public class Category implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 255)
    @Column(name = "NAME")
    private String name;
    @Column(name = "DATE_CREATED")
    @Temporal(TemporalType.DATE)
    private LocalDate dateCreated;
    @Size(max = 255)
    @Column(name = "DESCRIPTION")
    private String description;
    @JoinTable(name = "PRODUCT_CATEGORIES", joinColumns = {
    @JoinColumn(name = "CATEGORY_NAME", referencedColumnName = "NAME")}, inverseJoinColumns = {
    @JoinColumn(name = "PRODUCT_ID", referencedColumnName = "ID")})
    @ManyToMany
    private Collection<Product> productCollection;
    ...

Эти классы сущностей были сгенерированы с использованием среды netbeans. Отношение таблицы для объекта не было создано, поэтому я не знаю, как вставить/обновить Категории, к которым принадлежит Продукт.
Это мой код, который выполняет вставку/обновление.

@Override
public int update(Object value, Product t) {
    CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
    CriteriaUpdate<Product> cu = cb.createCriteriaUpdate(Product.class);

    cu.set(Product_.brand, t.getBrand());
    cu.set(Product_.id, t.getId());
    cu.set(Product_.name, t.getName());
    cu.set(Product_.quantity, t.getQuantity());
    cu.set(Product_.unitCost, t.getUnitCost());

     // cu.set(Product_.categoryCollection, t.getCategoryCollection());

    Root<Product> root = cu.getRoot();
    Predicate tester = cb.equal(root.get(Product_.id), value);
    cu.where(tester);

    Query q = getEntityManager().createQuery(cu);
    return q.executeUpdate();
} 

Класс метамодели продукта

...
public class Product_ {
     public static volatile SingularAttribute<Product, Integer> quantity;
     public static volatile CollectionAttribute<Product, Requisition> requisitionCollection;
     public static volatile CollectionAttribute<Product, Category> categoryCollection;
     public static volatile SingularAttribute<Product, Deal> dealId;
     public static volatile SingularAttribute<Product, Integer> unitCost;
     public static volatile SingularAttribute<Product, String> name;
     public static volatile CollectionAttribute<Product, Feature> featureCollection;
     public static volatile SingularAttribute<Product, Integer> id;
     public static volatile SingularAttribute<Product, Brand>    brand;
     ...

Из того, что я вижу, класс метамодели ожидает категорию, а не набор категорий. Пожалуйста, подскажите, как решить эту проблему.
программное обеспечение
netbeans 8.0.2
сервер Glassfish 4.1
jdk1.8.0_40


person blaze    schedule 04.05.2015    source источник
comment
Почему вы используете CriteriaUpdate? Поскольку вы, похоже, обновляете один продукт, почему бы просто не persist/merge продукта?   -  person Didier L    schedule 04.05.2015
comment
это сработало, спасибо за вашу помощь.   -  person blaze    schedule 04.05.2015


Ответы (1)


Вы не должны использовать CriteriaUpdate для простого обновления по идентификатору, когда у вас есть вся запись. Просто используйте

getEntiyManager().merge(t);
person Didier L    schedule 04.05.2015
comment
Мне также нужно вставить сделки во все продукты бренда, я думаю, что для этого требуется массовое обновление всех продуктов бренда. Поскольку слияние обновляет запись для объекта, как выполнить массовое обновление? - person blaze; 04.05.2015
comment
Это совсем другой вопрос, я предлагаю вам выполнить поиск запросов на обновление/вставку JPA и вернуться к SO, если у вас возникнут проблемы. - person Didier L; 04.05.2015