【发布时间】:2016-11-27 10:48:27
【问题描述】:
我在 Spring JPA/hibernate 环境中存在持久实体问题。我也在使用 Lombok Plugin 来减少样板代码。 基本上我有一个名为 Product 的实体,它与 SubProduct 有 oneToMany 关系:
@Entity
@Table(name="product")
@EqualsAndHashCode(exclude = {"productId"}, callSuper=false)
@ToString(includeFieldNames=true, callSuper=true)
@Data
public class Product implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="product_id")
private Integer productId;
@OneToMany(fetch = FetchType.EAGER, mappedBy="product"
, cascade ={CascadeType.ALL}, orphanRemoval=true)
private Set<SubProduct> subProducts;
}
这是我的子产品,它与名为 ProductVariantMap 的 joinTable 有另一个 oneToMany 关系:
@Entity
@Table(name="sub_product")
@EqualsAndHashCode(exclude = {"subId","product"})
@ToString(includeFieldNames=true, exclude = {"product"})
@Data
public class SubProduct implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="sub_id")
private Integer subId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id" )
private Product product;
@OneToMany(fetch = FetchType.EAGER,
mappedBy="productVariantMapId.subProduct"
, cascade = {CascadeType.ALL})
private List<ProductVariantMap> productVariantMaps;
}
这是我的 ProductVariantMap,其嵌入的 id 包含 productId、subId 和 variantId
@Entity
@Table(name="product_variant_map")
@EqualsAndHashCode
@ToString(includeFieldNames=true)
@Data
public class ProductVariantMap implements Serializable {
@EmbeddedId
private ProductVariantMapId productVariantMapId;
@Column(name="variant_value", nullable=false)
private String variantValue;
}
productVariantMapId:
@Embeddable
@EqualsAndHashCode(exclude = {"subProduct","product"})
@ToString(includeFieldNames=true,exclude = {"subProduct","product"})
@Data
public class ProductVariantMapId implements Serializable {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "sub_id" )
private SubProduct subProduct;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "product_id" )
private Product product;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "variant_id" )
private Variant variant;
}
最后但并非最不重要的是我的变体:
@Entity
@Table(name="variant")
@EqualsAndHashCode(exclude = {"variantId"})
@ToString(includeFieldNames=true)
@Data
public class Variant implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="variant_id")
private Integer variantId;
@Column(name="name", nullable=false)
private String name;
}
我的目标是在我执行 productRepository.saveAndFlush(product) 时能够一次性维持整个关系。请注意,所有主键都是由数据库序列生成器生成的,因此它在 saveAndFlush 之前为空。当我尝试执行上述操作时出现以下异常:
java.lang.NullPointerException
at org.hibernate.type.descriptor.java.AbstractTypeDescriptor.extractHashCode(AbstractTypeDescriptor.java:65)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:201)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:206)
at org.hibernate.type.EntityType.getHashCode(EntityType.java:355)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:241)
at org.hibernate.engine.spi.EntityKey.generateHashCode(EntityKey.java:61)
at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:54)
at org.hibernate.internal.AbstractSharedSessionContract.generateEntityKey(AbstractSharedSessionContract.java:459)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:162)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:788)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:391)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:316)
我跟踪了执行情况,似乎异常是由具有 null HashCode 的 Variant 类引起的,这不应该是这种情况,因为我为每个变量填充了不同的名称以供休眠区分(尽管 Id 尚不清楚)子产品(我试图在一个产品下保存 2 个子产品)。然后每个子产品将有两个 productVariantMap。
我希望剩下 1 个产品行、2 个子产品、4 个产品变体映射行和 2 个变体行。 是否有可能在 JPA 中一次性维持整个关系? 非常感谢
【问题讨论】:
标签: hibernate jpa spring-data-jpa lombok