我在Spring JPA/Hibernate環境中遇到持久化實體問題。我也使用Lombok插件來減少樣板代碼。 基本上我有一個實體,稱爲產品,其具有子產品一對多的關係:如何堅持一個具有兩級oneToMany關係的JPA實體?
@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;
}
,這是我的子產品,其具有與joinTable另一種一對多的關係稱爲ProductVariantMap:
@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(產品)。請注意,所有主鍵都由數據庫序列生成器生成,因此它在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)
我跟蹤的執行和它似乎異常是由variant類引起的具有空的hashCode這不應該是因爲我居住的變體具有不同的情況下名稱爲休眠區分(儘管Id尚不知道)每個子產品(我試圖保存2個子產品在一個產品下)。每個subProduct將有兩個productVariantMap。
我期望剩下1個產品行,2個子產品,4個產品變體映射行和2個變體行。 是否有可能在JPA中一直堅持整個關係? 非常感謝
之所以我的哈希和平等的方法是基於ID旁邊的其他領域是因爲我依靠數據庫ID生成器。如果我使用ID作爲唯一標識符,那麼Java會將集合中的新實體視爲一個實體,因爲它們都具有空ID,請參閱http://www.onjava.com/pub/a/onjava/2006/09/13 /dont-let-hibernate-steal-your-identity.html – user3391672
在equals方法中看到這一行:if(id == null)return false;沒有Id的新對象將永遠不會相同。 –
如果我刪除Embeddable類中的manyToOne,hibernate如何知道某個特定productVariantMap具有哪個sub_id或product_id?請記住,所有實體標識都爲空saveAndFlush – user3391672