JPA, гибернация, Java. Составной первичный ключ, один из них также является внешним ключом

#java #mysql #hibernate #jpa #composite-primary-key

#java #mysql #гибернация #jpa #составной первичный ключ

Вопрос:

У меня проблема, описанная вкратце в названии. Может кто-нибудь сказать мне, как я могу получить ту же базу данных, используя JPA?

 create table ALBUM
( 
 IdAlbum int, 
 AlbumName varchar(35) not null, 
 UrlOfAlbum varchar(60) not null,
 Primary Key(IdAlbum) 
);
create table ARTIST
(
 IdArtist int, 
 ArtistName varchar(35) not null, 
 Primary Key(IdArtist) 
);
create table TRACK
(
 IdTrack int,
 IdAlbum int,
 IdArtist int,
 TrackName varchar(35) not null,
 Primary Key(IdTrack, IdAlbum),
 Foreign Key(IdAlbum) references Album(IdAlbum),
 Foreign Key(IdArtist) references Artist(IdArtist)
);
 

Ответ №1:

Просто поместите столбцы во встроенный ключ и сохраните связь в основном классе:

 @Embeddable
class TrackId
{
    private Integer idAlbum;
    private Integer idTrack;
    // getters, setters, equals and hashCode
}

@Entity
class Track
{
     @EmbeddedId
     TrackId trackId;

     @ManyToOne
     @MapsId("idAlbum")
     @JoinColumn(name = "idAlbum", referencedColumnName = "idAlbum")
      private Album album = null;

      ....
}
 

Ответ №2:

Вам нужно использовать «производную идентификацию»:

 @Entity
public class Album {
    @Id
    @Column(name = "IdAlbum")
    private Integer id;

    @Column(name = "AlbumName")
    private String name;

    ...
}

@Embeddable
public class TrackID {
    @Column(name = "IdTrack")
    private Integer trackID;

    @Column(name = "IdAlbum")
    private Integer albumID; // NB: corresponds to PK type of Album

    ...
}

@Entity
public class Track {
    @EmbeddedId
    TrackID id;

    @ManyToOne
    @MapsId("albumID") // NB: maps 'albumID' attribute of embedded id
    @JoinColumn(name = "IdAlbum", referencedColumnName = "IdAlbum")
    private Album album;

    ...
}
 

Производные идентификаторы обсуждаются в спецификации JPA 2.1, раздел 2.4.1.

Ответ №3:

Вы должны определить класс composite-id с помощью @javax.persistence.Embeddable

 @Embeddable
public class TrackPK {
    @Column(name = "IdTrack")
    private Integer trackId;
    @JoinColumn(name = albumId, referencedColumnName = "IdAlbum")
    private Album album;
    // setters amp; getters
    // you also have to implement equals and hashCode
}
 

С этого момента есть два пути. Вы можете использовать TrackPK объект внутри своего Track класса с @EmbeddedId аннотацией (как предложил Висковский), или вы можете использовать @IdClass(TrackPK.class) вне своего Track вместе с @Entity аннотацией. Вам также придется дублировать поля и параметры из TrackPK класса в Track , и использовать ту же реализацию equals и hashCode для Track класса, и добавить @Id аннотацию к обоим полям.

Я знаю, это звучит как много, но это просто копирование-вставка всей внутренней части TrackPK, и это превращается track.getTrackPK().getAlbum() в track.getAlbum() , избавляя вас даже от прямого использования этого класса TrackPK. Вы можете просто позволить JPA обработать это.