簡體   English   中英

使用主鍵作為外鍵映射@OneToMany關系

[英]Mapping a @OneToMany relation with a primary key as foreign key

我正在嘗試映射JPA下圖中描述的一對多表關系:

活動圖JPA

如可以看到的, "activity_property"表使用與復合主鍵(id,name)和列"id"是一個外鍵列"id"在表中"activity"

我當前的實體是通過這種方式映射的(為清楚起見,一些輔助方法已被省略):

Activity.java

@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;
}

ActivityProperty.java

@Entity
@Getter
@Setter
@Table(name = "activity_property")
public class ActivityProperty {
    @EmbeddedId
    private ActivityPropertyId id;

    private String value;

    @Enumerated(EnumType.STRING)
    private PropertyType type;
}

ActivityPropertyId.java

@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的屬性用於此目的。

因此,要么創建一個從ActivityPropertyActivity的反向引用,然后使用由映射的反向引用,要么必須使用@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM