我的目标是使用所有过滤器克隆实体“产品”。
例如,我有一个实体(为简单起见,省略了getter和setter):
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ElementCollection()
private List<Filter> filters = new ArrayList<Filter>();
}
和可嵌入的类:
@Embeddable
public class Filter {
@Column(length = 255, nullable = false)
private String name;
@Column(nullable = false)
private long variant = -1;
}
现在,如果我这样做了:
entityManager.detach(product);
product.setId(null);
productService.save(product);
我将获得产品实体的副本,但带有原始产品的过滤器。同时,原始产品最终将根本没有任何过滤器。
那是过滤器的表格行的样子:
之前:
product_id; name; variant
217; "f2"; 86
之后:
product_id; name; variant
218; "f2"; 86
我尝试从列表中分离出每个过滤器,但这给了我错误。
如何使其与实体复制过滤器?
编辑:添加了完整的产品和过滤器代码:
package com.serhiy1.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.SortableField;
import org.joda.time.DateTime;
import com.serhiy1.constraint.LocalePacker;
@Indexed
@Entity
@EntityListeners(ProductListener.class)
public class Product {
public static final int PRICE_PER_ONE = 0;
public static final int PRICE_PER_METER = 1;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long code;
private String name = "";
private String grouping = "";
@Field
@Column(columnDefinition="text")
private String title = "";
@Field
@Column(columnDefinition="text")
private String intro = "";
@Column(columnDefinition="text")
private String content = "";
@Field
@Column(columnDefinition="text")
private String contentHtml = "";
private String locale = "en";
private Long parentId = 0L;
private DateTime time;
private DateTime timeMod;
private Long balanceRequired = 0L;
private Integer index = 0;
@Field(name = "price_sort")
@SortableField(forField = "price_sort")
private Double price = 0.0;
private Integer pricePer;
@Transient
private long childrenCount = 0;
@Transient
private String image = "";
@Transient
private List<String> images = new ArrayList<String>();
@ManyToOne(targetEntity = User.class)
@JoinColumn(nullable = false, name = "user_id")
@LazyCollection(LazyCollectionOption.FALSE)
private User user;
@ManyToOne(targetEntity = Product.class)
@JoinColumn(nullable = true, name = "category_id")
@LazyCollection(LazyCollectionOption.FALSE)
private Product category;
@ElementCollection()
private List<Filter> filters = new ArrayList<Filter>();
@ElementCollection()
private List<Modifier> modifiers = new ArrayList<Modifier>();
public Product() {
}
@Transient
private String _title = "";
@Transient
private String _intro = "";
@Transient
private String _content = "";
@Transient
private String _contentHtml = "";
public void pack(String locale, List<String> locales) {
if(locale.contains("_")) return;
title = LocalePacker.repack(locale, _title, title, locales);
intro = LocalePacker.repack(locale, _intro, intro, locales);
content = LocalePacker.repack(locale, _content, content, locales);
contentHtml = LocalePacker.repack(locale, _contentHtml, contentHtml, locales);
}
public void unpack(String locale) {
_title = LocalePacker.unpackStr(locale, title).getOrDefault(locale, "");
_intro = LocalePacker.unpackStr(locale, intro).getOrDefault(locale, "");
_content = LocalePacker.unpackStr(locale, content).getOrDefault(locale, "");
_contentHtml = LocalePacker.unpackStr(locale, contentHtml).getOrDefault(locale, "");
}
public void copy(String landFrom, String landTo) {
title = LocalePacker.copyLang(title, landFrom, landTo);
intro = LocalePacker.copyLang(intro, landFrom, landTo);
content = LocalePacker.copyLang(content, landFrom, landTo);
contentHtml = LocalePacker.copyLang(contentHtml, landFrom, landTo);
}
public Modifier getModifier(String name) {
for(Modifier m: modifiers) {
if(m.getName().equals(name)) return m;
}
return null;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public long getCode() {
return code == null ? id : code;
}
public void setCode(long code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrouping() {
return grouping;
}
public void setGrouping(String grouping) {
this.grouping = grouping;
}
public String getTitle() {
return _title;
}
public void setTitle(String title) {
this._title = title;
}
public String getIntro() {
return _intro;
}
public void setIntro(String intro) {
this._intro = intro;
}
public String getContent() {
return _content;
}
public void setContent(String content) {
this._content = content;
}
public String getContentHtml() {
return _contentHtml;
}
public void setContentHtml(String contentHtml) {
this._contentHtml = contentHtml;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public long getParentId() {
return parentId;
}
public void setParentId(long parentId) {
this.parentId = parentId;
}
public DateTime getTime() {
return time;
}
public void setTime(DateTime time) {
this.time = time;
}
public DateTime getTimeMod() {
return timeMod;
}
public void setTimeMod(DateTime timeMod) {
this.timeMod = timeMod;
}
public long getBalanceRequired() {
return balanceRequired == null ? 0L : balanceRequired;
}
public void setBalanceRequired(long balanceRequired) {
this.balanceRequired = balanceRequired;
}
public Integer getIndex() {
//return index == null ? 1000 : index;
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public double getPrice() {
return price == null ? 0.0 : price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPricePer() {
return pricePer == null ? PRICE_PER_METER : pricePer;
}
public void setPricePer(int pricePer) {
this.pricePer = pricePer;
}
public long getChildrenCount() {
return childrenCount;
}
public void setChildrenCount(long childrenCount) {
this.childrenCount = childrenCount;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Product getCategory() {
return category;
}
public void setCategory(Product category) {
this.category = category;
}
public List<Filter> getFilters() {
return filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
}
public List<Modifier> getModifiers() {
return modifiers;
}
public void setModifiers(List<Modifier> modifiers) {
this.modifiers = modifiers;
}
public boolean isCategory() { return price < 0; }
@Override
public String toString() {
return "Article{" +
"id=" + id +
'}';
}
}
..
package com.serhiy1.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Transient;
@Embeddable
public class Filter {
@Column(length = 255, nullable = false)
private String name;
@Column(nullable = false)
private long variant = -1;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVariant() {
return variant;
}
public void setVariant(long variant) {
this.variant = variant;
}
}
答案 0 :(得分:1)
我做了一个小型项目,试图复制您的问题。
这是一个具有H2数据库和JPA(Hibernate实现)的String Boot项目。
在启动时,Hibernate创建2个表:
create table product (
id bigint not null,
primary key (id)
)
和
create table product_filters (
product_id bigint not null,
name varchar(255) not null,
variant bigint not null
)
在创建过滤器的产品上,两个表都将插入:
insert
into
product
(id)
values
(1)
和
insert
into
product_filters
(product_id, name, variant)
values
(1, "f1", 1)
之后:
entityManager.detach(product);
product.setId(null);
productService.save(product);
休眠问题:
delete
from
product_filters
where
product_id=1
这是正常的,因为filters
是ElementCollection,因此它完全由实体Product
拥有。在productService.save(product)
上,Hibernate检测到filters
集合已绑定到另一个Product
,因此在创建新集合之前将其删除(从product_filter
表中删除)。
克服删除的唯一方法是重新创建集合:
List<Filter> filters = new ArrayList<Filter>();
filters.addAll(oldFilters);
product.setFilters(filters);
总而言之,这是解决方案:
// To trigger the fetch
List<Filter> filters = new ArrayList<Filter>(product.getFilters());
entityManager.detach(product);
product.setId(null);
product.setFilters(filters);
productService.save(product);