Domanda Hibernate relazione molti a uno senza chiave primaria o tabella di join


Problema

Vorrei iniziare dicendo che mi rendo conto che la struttura del database è atroce, ma non posso modificarla in questo momento.

Detto questo, ho la necessità di creare una relazione bi-direzionale one-to-many in Hibernate (4.2.1) che non comporta chiavi primarie (solo una chiave univoca sul lato "genitore" della relazione) e no unisciti alle tabelle La chiave esterna che rappresenta questa relazione è un backpointer dal "figlio" al "genitore" (vedi sotto). Ho cercato e provato diverse configurazioni di annotazioni senza fortuna. È quello che sto chiedendo possibile?

Banca dati

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
);

Riferimento:

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

Giava

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

}

Qualsiasi aiuto sarebbe molto apprezzato!!


14
2018-06-07 17:25


origine


risposte:


Prima di tutto, in un'associazione bidirezionale, c'è sempre un lato proprietario, che definisce la mappatura, e una parte inversa, contrassegnata dalla presenza del mappedBy attributo.

In un'associazione OneToMany, il lato proprietario è sempre il lato più (PartRelease nel tuo caso).

Inoltre, una colonna di join, per impostazione predefinita, fa riferimento all'ID dell'entità a cui fa riferimento. Dal momento che non è quello che vuoi, devi specificare il nome della colonna di riferimento.

E ovviamente, la colonna RELEASES deve essere mappata:

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;

}

Le associazioni sono ben descritte in la documentazione. Dovresti leggerlo.


27
2018-06-07 21:37



Come spiegato in Questo articolo, ogni volta che devi mappare a @ManyToOne usando una colonna Chiave non primaria sul lato genitore, devi usare il referencedColumnName attributo del @JoinColumn annotazione.

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

ero solito FetchType.LAZY per il @ManyToOne perché per impostazione predefinita viene utilizzato il recupero EAGER, che è molto male per le prestazioni.


1
2017-08-15 13:37