[英]Mapping a @OneToMany relation with a primary key as foreign key
我正在嘗試映射JPA下圖中描述的一對多表關系:
如可以看到的, "activity_property"
表使用與復合主鍵(id,name)
和列"id"
是一個外鍵列"id"
在表中"activity"
。
我當前的實體是通過這種方式映射的(為清楚起見,一些輔助方法已被省略):
@Entity
@Getter
@Setter
public class Activity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "act_id_generator")
@SequenceGenerator(name = "act_id_generator", sequenceName = "activity_id_seq", allocationSize = 1, initialValue = 1)
private Integer id;
private String name;
@OneToMany(mappedBy = "id.activityId", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ActivityProperty> properties;
}
@Entity
@Getter
@Setter
@Table(name = "activity_property")
public class ActivityProperty {
@EmbeddedId
private ActivityPropertyId id;
private String value;
@Enumerated(EnumType.STRING)
private PropertyType type;
}
@Embeddable
@Getter
@Setter
@ToString
public class ActivityPropertyId implements Serializable {
@Column(name = "id")
private Integer activityId;
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ActivityPropertyId that = (ActivityPropertyId) o;
return activityId.equals(that.activityId) &&
name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(activityId, name);
}
}
當我嘗試通過這種方式堅持一項活動時:
Activity activity = createActivity("Activity_1");
activity.addProperty(ActivityProperty.from("Prop1", "value1", PropertyType.PARAMETER));
activityDAO.persist(activity);
我可以在Hibernate中看到以下痕跡:
Hibernate: call next value for activity_id_seq
Hibernate: insert into activity (name, id) values (?, ?)
Hibernate: insert into activity_property (type, value, id, name) values (?, ?, ?, ?)
05-05-2019 12:26:29.623 [main] WARN o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - SQL Error: 23502, SQLState: 23502
05-05-2019 12:26:29.624 [main] ERROR o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - NULL not allowed for column "ID"; SQL statement:
insert into activity_property (type, value, id, name) values (?, ?, ?, ?) [23502-199]
這似乎為自動生成的編號Activity
沒有在第二插入了已使用ActivityProperty
。
我不知道如何正確映射這種關系。我的JPA注釋中是否缺少任何內容?
mappedBy
屬性用於指示此關系不用於持久化,而mappedBy
的屬性用於此目的。
因此,要么創建一個從ActivityProperty
到Activity
的反向引用,然后使用由映射的反向引用,要么必須使用@JoinColumn
聲明外鍵。
看起來像。 屬性name
指向目標表中外鍵的名稱。
@JoinColumn(name = "id", nullable = false)
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<ActivityProperty> properties;
更新2019年5月6日當您啟用了級聯時,您應該並從關系中寫入ID,您必須將activityId字段設置為只讀:
@Column(name = "id", insertable = false, updateable = false)
private Integer activityId;
在此處閱讀有關關系映射的更多信息: https : //thoughts-on-java.org/ultimate-guide-association-mappings-jpa-hibernate/
據我所知,JPA不通過cascade
操作支持該功能。 您向JPA提出的要求過多。 我沒有特定的參考說明,但是使用下面的代碼,您可以盡可能地接近。 它不會運行,因為(至少)休眠狀態不知道如何自動將activity.id
映射到ActivityProperty
類的PK。
@Entity
@Getter
@Setter
@Table(name = "activity_property")
@IdClass(ActivityPropertyId.class)
public class ActivityProperty {
@ManyToOne
@Id
@JoinColumn(name="id", referencedColumnName="id")
private Activity activity;
@Id
private String name;
private String value;
}
@Getter
@Setter
@ToString
public class ActivityPropertyId implements Serializable {
public ActivityPropertyId() {}
@Column(name = "id")
private Integer activity;
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ActivityPropertyId that = (ActivityPropertyId) o;
return activity.equals(that.activity) &&
name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(activity, name);
}
}
這將給出例外
原因:java.lang.IllegalArgumentException:無法將java.lang.Integer字段model.ActivityPropertyId.activity設置為model.Activity
而且我還沒有找到解決這個問題的好方法。 恕我直言, cascade
是傻瓜的天堂,您應該自己保存ActivityProperty
實例,並使用雙向映射僅用於查詢。 這確實是它打算使用的方式。 如果您通過級聯對OneToMany
列表執行一些簡單的保存操作,並查看生成的SQL,您將看到可怕的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.