web-dev-qa-db-ja.com

主キーまたは結合テーブルのないHibernate多対1関係

問題

まず、データベース構造がひどいものであることに気付きましたが、現時点では変更できません。

そうは言っても、主キー(関係の「親」側にある一意のキーのみ)およびテーブルを結合します。この関係を表す外部キーは、「子」から「親」へのバックポインターです(以下を参照)。さまざまな異なる注釈構成を検索して試してみましたが、運はありません。私が求めているのは可能ですか?

データベース

GLOBAL_PART

CREATE TABLE "GLOBAL_PART" (    
    "GLOBAL_PART_ID" NUMBER NOT NULL,
    "RELEASES" NUMBER,
    CONSTRAINT "GLOBAL_PART_PK" PRIMARY KEY ("GLOBAL_PART_ID"),
    CONSTRAINT "GLOBAL_PART_RELEASES_UK" UNIQUE ("RELEASES")
);

PART_RELEASE

CREATE TABLE "PART_RELEASE" (
    "PART_RELEASE_ID" NUMBER NOT NULL,
    "COLLECTION_ID" NUMBER,
    CONSTRAINT "PART_RELEASE_PK" PRIMARY KEY ("PART_RELEASE_ID"),
    CONSTRAINT "GLOBAL_PART_RELEASE_FK" FOREIGN KEY ("COLLECTION_ID")
        REFERENCES "GLOBAL_PART" ("RELEASES") ON DELETE CASCADE ENABLE
);

参照:

PART_RELEASE                 GLOBAL_PART
-------------------          ------------
PART_RELEASE_ID (PK)         GLOBAL_PART_ID (PK)
COLLECTION_ID -------------> RELEASES (UK)

Java

GlobalPart.Java

@Entity
@Table(name = "GLOBAL_PART")
@SequenceGenerator(name = "SEQUENCE_GENERATOR", sequenceName = "GLOBAL_PART_SEQ")
public class GlobalPart extends ModelBase implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "GLOBAL_PART_ID", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_GENERATOR")
    private Long globalPartId;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name = "COLLECTIONGID")
    private Set<PartRelease> releases;

    public Long getGlobalPartId() {
        return globalPartId;
    }

    public void setGlobalPartId(Long globalPartId) {
        this.globalPartId = globalPartId;
    }

    public Set<PartRelease> getReleases() {
        return releases;
    }

    public void setReleases(Set<PartRelease> releases) {
        this.releases = releases;
    }

}

PartRelease.Java

@Entity
@Table(name = "PART_RELEASE")
@SequenceGenerator(name = "SEQUENCE_GENERATOR", sequenceName = "PART_RELEASE_SEQ")
public class PartRelease extends ModelBase implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "PART_RELEASE_ID", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_GENERATOR")
    private String partReleaseId;

    @ManyToOne
    @JoinColumn(name = "RELEASES")
    private GlobalPart globalPart;

    public String getPartReleaseId() {
        return partReleaseId;
    }

    public void setPartReleaseId(String partReleaseId) {
        this.partReleaseId = partReleaseId;
    }

    public GlobalPart getGlobalPart() {
        return globalPart;
    }

    public void setGlobalPart(GlobalPart globalPart) {
        this.globalPart = globalPart;
    }

}

どんな助けも大歓迎です!

16
chrismborland

まず、双方向の関連付けでは、マッピングを定義する所有者側と、mappedBy属性の存在によってマークされる逆側が常に存在します。

OneToManyアソシエーションでは、所有者側は常に多側(あなたの場合はPartRelease)です。

さらに、デフォルトでは、結合列は参照するエンティティのIDを参照します。必要なものではないため、参照される列名を指定する必要があります。

そしてもちろん、RELEASES列はマップする必要があります。

public class GlobalPart extends ModelBase implements Serializable {

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "globalPart")
    private Set<PartRelease> partReleases;

    @Column(name = "RELEASES")
    private Long releasesNumber;
}

public class PartRelease extends ModelBase implements Serializable {
    @ManyToOne
    @JoinColumn(name = "COLLECTION_ID", referencedColumnName = "RELEASES")
    private GlobalPart globalPart;

}

関連は ドキュメント で詳しく説明されています。読んでください。

32
JB Nizet

この記事 で説明されているように、親側で非プライマリキー列を使用して@ManyToOneをマップする必要がある場合は、常にreferencedColumnName属性を使用する必要があります@JoinColumnアノテーション。

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
    name = "RELEASES", 
    referencedColumnName = "COLLECTIONGID"
)

FetchType.LAZY@ManyToOneを使用しました。これは、デフォルトでEAGERフェッチが使用されるためです。これは パフォーマンスにとって非常に悪い です。

2
Vlad Mihalcea