Java >> Java tutorial >  >> Tag >> hibernate

Blanding af arvekortlægningsstrategier med Hibernate

Arv er et af nøglebegreberne i Java, og de fleste udviklingsteams foretrækker at bruge det i deres domænemodel. Desværre understøtter relationelle tabelmodeller ikke begrebet arv. JPA-specifikationen definerer flere kortlægningsstrategier for at bygge bro mellem den objektorienterede og den relationelle verden. Jeg forklarede dem meget detaljeret i min Ultimate Guide to Inheritance Mappings.

Da jeg for nylig underviste i disse kortlægningsstrategier på en intern workshop, blev jeg spurgt, om det er muligt at kombinere InheritanceType.SINGLE_TABLE med InheritanceType.JOINED . Dette er ikke et ualmindeligt spørgsmål, især hvis teamet arbejder på enorme og komplekse virksomhedsapplikationer. Men svaret på det spørgsmål er:Nej. Baseret på JPA-specifikationen kan persistensudbydere understøtte dette, men det behøver de ikke. Hibernate understøtter ikke blandingen af ​​flere strategier.

Men i de fleste tilfælde kan du kombinere din arvekortlægning med en @SecondaryTable kortlægning for at nå dine kortlægningsmål. I denne artikel vil jeg vise dig, hvordan du kortlægger dette arvehierarki

til følgende tabelmodel.

Definition af din arvekortlægning

I det første trin skal du definere din arvekortlægning. Når du bruger InheritanceType.SINGLE_TABLE , kortlægger du alle klasser i arvshierarkiet til den samme databasetabel. Typen af ​​hver post bliver gemt i en diskriminatorkolonne. Jeg forklarede andre kortlægningsstrategier i min guide til kortlægning af arv.

For at definere denne kortlægning skal du annotere din superklasse med @Entity og @Inheritance(strategy =InheritanceType.SINGLE_TABLE) . Du kan også tilføje @DiscriminatorColumn annotation for at definere navnet på din diskriminatorkolonne.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public abstract class ChessTournament { ... }

Definitionen af ​​underklasserne er ligetil. De behøver kun at udvide superklassen, og du skal annotere dem med @Entity .

@Entity
public class ChessSwissTournament extends ChessTournament { ... }

Og det samme er tilfældet for alle andre niveauer i arvehierarkiet.

@Entity
public class ChessSwissTournamentForMen extends ChessSwissTournament { ... }
@Entity
public class ChessSwissTournamentForWomen extends ChessSwissTournament { ... }

Alle entitetsobjekter i dette nedarvningshierarki vil blive mappet til tabellen defineret for superklassen. Hvis du ikke anmærker det med en @Tabel annotation, vil din persistensudbyder bruge det simple klassenavn som tabelnavn.

Kombinering af arvetilknytninger med en @Secondary Tabel

Når du har tilknyttet alle klasser i dit arvehierarki til den samme databasetabel, kan du definere en sekundær tabel for hver af dem. Dette distribuerer attributterne for enhedsklassen til 2 eller flere databasetabeller. Ved at gøre det kommer du relativt tæt på den tabelkortlægning, du ville få ved at bruge en kombination af InheritanceType.SINGLE_TABLE og InheritanceType.JOINED .

Lad os tilføje en @SecondaryTable anmærkning til ChessSwissTournament , ChessSwissTournamentForMen og ChessSwissTournamentForWomen enhedsklasser.

I eksemplet med ChessSwissTournament enhedsklasse, vil jeg gemme det maksimalt tilladte antal spillere til denne turnering i maxPlayers attribut. Jeg vil knytte det til en kolonne med samme navn i ChessSwissTournament bord. Dette kræver en @SecondaryTable annotation på klassen for at definere navnet på den sekundære databasetabel. Denne annotering kan gentages, og du kan definere flere sekundære tabeller for din enhedsklasse. Og du skal annotere attributten med en @Column anmærkning og referer til navnet på den sekundære tabel.

@Entity
@SecondaryTable(name = ChessSwissTournament.TABLE_NAME)
public class ChessSwissTournament extends ChessTournament { 
    static final String TABLE_NAME = "ChessSwissTournament";

    @Column(table = TABLE_NAME)
    private int maxPlayers;

    private int rounds;

    // getter and setter methods
}

Den sekundære tabelkortlægning af ChessSwissTournament klasse bliver nedarvet af alle underklasser. På hver underklasse kan du definere yderligere sekundære tabeller ved hjælp af @SecondaryTable anmærkninger. I dette eksempel bruger jeg det til at kortlægge antallet af spillere med en stormestertitel, der spiller i en ChessSwissTournamentForMen til en kolonne i en separat tabel.

@Entity
@SecondaryTable(name = ChessSwissTournamentForMen.TABLE_NAME)
public class ChessSwissTournamentForMen extends ChessSwissTournament {

    static final String TABLE_NAME = "ChessSwissTournamentMen";

    @Column(table = TABLE_NAME)
    private int gm;

    // getter and setter methods
}

Og til ChessSwissTournamentForWomen enhed, vil jeg kortlægge antallet af spillere med en Woman Grand Master-titel til en kolonne i en anden, separat tabel.

@Entity
@SecondaryTable(name = ChessSwissTournamentForWomen.TABLE_NAME)
public class ChessSwissTournamentForWomen extends ChessSwissTournament {

    static final String TABLE_NAME = "ChessSwissTournamentWomen";

    @Column(table = TABLE_NAME)
    private int wgm;

    // getter and setter methods
}

Baseret på denne kortlægning kortlægger Hibernate enhedsklasserne til den tabelmodel, som jeg viste dig i introduktionen af ​​denne artikel. Lad os bruge denne kortlægning til at fortsætte en ny ChessSwissTournamentForMen enhedsobjekt.

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

ChessSwissTournamentForMen chessSwissTournamentForMen = new ChessSwissTournamentForMen();
chessSwissTournamentForMen.setName("My local tournament");
chessSwissTournamentForMen.setMaxPlayers(64);
chessSwissTournamentForMen.setRounds(7);
chessSwissTournamentForMen.setGm(4);
em.persist(chessSwissTournamentForMen);

em.getTransaction().commit();
em.close();

Efter at have aktiveret min anbefalede udviklingskonfiguration, kan du se i log-outputtet, at Hibernate har indsat nye poster i:

  • Skakturnering tabel med alle attributter defineret af ChessTournament klasse,
  • ChessSwissTournament tabel med alle attributter tilføjet af ChessSwissTournament klasse og
  • ChessSwissTournamentMen tabel med alle attributter tilføjet af ChessSwissTournamentMen klasse.
17:36:06,996 DEBUG SQL:144 - select nextval ('tournament_seq')
17:36:07,032 DEBUG SQL:144 - insert into ChessTournament (endDate, name, startDate, version, rounds, type, id) values (?, ?, ?, ?, ?, 'ChessSwissTournamentForMen', ?)
17:36:07,037 DEBUG SQL:144 - insert into ChessSwissTournament (maxPlayers, id) values (?, ?)
17:36:07,039 DEBUG SQL:144 - insert into ChessSwissTournamentMen (gm, id) values (?, ?)

Konklusion

Som du så i denne artikel, kan du bruge @SecondaryTable, selvom Hibernate ikke understøtter blanding af nedarvskortstrategier. annotation for at definere yderligere tabeller, som din enhedsklasse bliver knyttet til. Dette giver dig mulighed for at tilknytte dine enhedsklasser til en tabelstruktur, der ligner kombinationen af ​​InheritanceType.SINGLE_TABLE og InheritanceType.JOINED .

Når du bruger dette, skal du være opmærksom på, at for hver forespørgsel, der vælger en af ​​underklasserne, vil Hibernate inkludere en JOIN-klausul til alle sekundære tabeller defineret af den underklasse og dens superklasser. Dette øger kompleksiteten af ​​SQL-sætningen og sinker dens udførelse.

Sådan en kompleks kortlægning gør det også meget sværere at forstå og vedligeholde dit persistenslag. Derfor anbefaler jeg, at du forenkler din kortlægning så meget som muligt og ikke bruger en sekundær tabelkortlægning på flere niveauer i dit arvehierarki.


Java tag