En oversigt over identifikatorer i dvale / JPA

1. Introduktion

Identifikatorer i dvale repræsenterer en enheds primære nøgle. Dette indebærer, at værdierne er unikke, så de kan identificere en bestemt enhed, at de ikke er null, og at de ikke vil blive ændret.

Dvale giver et par forskellige måder at definere identifikatorer på. I denne artikel gennemgår vi hver metode til kortlægning af enheds-id'er ved hjælp af biblioteket.

2. Enkle identifikatorer

Den mest ligefremme måde at definere en identifikator på er ved hjælp af @Id kommentar.

Enkle id'er kortlægges ved hjælp af @Id til en enkelt egenskab af en af ​​disse typer: Java primitive og primitive wrapper typer, String, Date, BigDecimal, BigInteger.

Lad os se et hurtigt eksempel på at definere en enhed med en primær nøgle af typen lang:

@Entity public class Student {@Id privat lang studentId; // standard konstruktør, getters, setters}

3. Genererede identifikatorer

Hvis vi ønsker, at den primære nøgleværdi skal genereres automatisk for os, vi kan tilføje @GeneratedValue kommentar.

Dette kan bruge 4 generationstyper: AUTO, IDENTITET, SEKVENS, TABEL.

Hvis vi ikke angiver en værdi eksplicit, er generationstypen som standard AUTO.

3.1. AUTO Generation

Hvis vi bruger standardgenereringstypen, bestemmer persistensudbyderen værdier baseret på typen af ​​den primære nøgleattribut. Denne type kan være numerisk eller UUID.

For numeriske værdier er generationen baseret på en sekvens eller en tabelgenerator, mens UUID værdier bruger UUIDGenerator.

Lad os se et eksempel på kortlægning af en enheds primærnøgle ved hjælp af AUTO-genereringsstrategi:

@Entity public class Student {@Id @GeneratedValue privat lang studentId; // ...}

I dette tilfælde vil de primære nøgleværdier være unikke på databaseniveau.

En interessant funktion introduceret i Hibernate 5 er UUIDGenerator. For at bruge dette er alt, hvad vi skal gøre, at erklære en id af typen UUID med @GeneratedValue kommentar:

@Entity offentlig klasse Kursus {@Id @GeneratedValue privat UUID kursId; // ...}

Dvaletilstand genererer et id med formularen “8dd5f315-9788-4d00-87bb-10eed9eff566”.

3.2. IDENTITET Generation

Denne type generation er afhængig af IdentityGenerator som forventer værdier genereret af en identitet kolonne i databasen, hvilket betyder at de automatisk øges.

For at bruge denne generationstype behøver vi kun at indstille strategi parameter:

@Entity public class Student {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) privat lang studentId; // ...}

En ting at bemærke er, at IDENTITY generation deaktiverer batchopdateringer.

3.3. SEKVENS Generation

For at bruge et sekvensbaseret id giver Hibernate SequenceStyleGenerator klasse.

Denne generator bruger sekvenser, hvis de understøttes af vores database, og skifter til tabelgenerering, hvis de ikke er det.

For at tilpasse sekvensnavnet kan vi bruge @GenericGenerator kommentar med SequenceStyleGenerator-strategi:

@Entity offentlig klasse bruger {@Id @GeneratedValue (generator = "sekvensgenerator") @GenericGenerator (navn = "sekvensgenerator", strategi = "org.hibernate.id.enhanced.SequenceStyleGenerator", parametre = {@Parameter ( name = "sequence_name", value = "user_sequence"), @Parameter (name = "initial_value", value = "4"), @Parameter (name = "increment_size", value = "1")}) privat lang brugerId; // ...}

I dette eksempel har vi også indstillet en startværdi for sekvensen, hvilket betyder at den primære nøglegenerering starter ved 4.

SEKVENS er den generationstype, der anbefales i dvale-dokumentationen.

De genererede værdier er unikke pr. Sekvens. Hvis du ikke angiver et sekvensnavn, genbruger dvaletilstand det samme igen dvale_sekvens til forskellige typer.

3.4. TABEL Generation

Det TableGenerator bruger en underliggende databasetabel, der indeholder segmenter af identifikationsgenereringsværdier.

Lad os tilpasse tabelnavnet ved hjælp af @TabelGenerator kommentar:

@Entity public class Department {@Id @GeneratedValue (strategi = GenerationType.TABLE, generator = "tabel-generator") @TableGenerator (navn = "tabel-generator", tabel = "dep_ids", pkColumnName = "seq_id", valueColumnName = "seq_value") privat lang depId; // ...}

I dette eksempel kan vi se, at andre attributter som f.eks pkColumnName og valueColumnName kan også tilpasses.

Ulempen ved denne metode er, at den ikke skaleres godt og kan påvirke ydeevnen negativt.

For at opsummere vil disse fire generationstyper resultere i, at lignende værdier genereres, men bruger forskellige databasemekanismer.

3.5. Brugerdefineret generator

Hvis vi ikke ønsker at bruge nogen af ​​de ikke-kasserede strategier, vi kan definere vores brugerdefinerede generator ved at implementere IdentifierGenerator interface.

Lad os oprette en generator, der bygger identifikatorer, der indeholder en Snor præfiks og et tal:

offentlig klasse MyGenerator implementerer IdentifierGenerator, konfigurerbar {privat streng præfiks; @ Override offentlig Serialiserbar generere (SharedSessionContractImplementor session, Objekt obj) kaster HibernateException {String-forespørgsel = String.format ("vælg% s fra% s", session.getEntityPersister (obj.getClass (). GetName (), obj) .getIdentifierPropertyName ( ), obj.getClass (). getSimpleName ()); Stream ids = session.createQuery (forespørgsel) .stream (); Lang max = ids.map (o -> o.replace (præfiks + "-", "")) .mapToLong (Long :: parseLong) .max () .orElse (0L); returpræfiks + "-" + (max + 1); } @Override public void configure (Type type, Properties egenskaber, ServiceRegistry serviceRegistry) kaster MappingException {prefix = properties.getProperty ("prefix"); }}

I dette eksempel vi tilsidesætter frembringe() metode fra IdentifierGenerator interface og find først det højeste tal fra formularens eksisterende primære nøgler præfiks-XX.

Derefter tilføjer vi 1 til det maksimale antal fundet og tilføjer præfiks ejendom for at opnå den nyligt genererede id-værdi.

Vores klasse implementerer også Konfigurerbar interface, så vi kan indstille præfiks ejendomsværdi i konfigurer () metode.

Lad os derefter tilføje denne brugerdefinerede generator til en enhed. For det, vi kan bruge @GenericGenerator kommentar med en strategi parameter, der indeholder det fulde klassenavn på vores generatorklasse:

@Entity offentlig klasse Produkt {@Id @GeneratedValue (generator = "prod-generator") @GenericGenerator (navn = "prod-generator", parametre = @Parameter (navn = "præfiks", værdi = "prod"), strategi = "com.baeldung.hibernate.pojo.generator.MyGenerator") privat strengprodukt; // ...}

Bemærk også, at vi har sat præfiksparameteren til "prod".

Lad os se en hurtig JUnit-test for en klarere forståelse af de genererede id-værdier:

@Test offentlig ugyldig nårSaveCustomGeneratedId_thenOk () {Produkt produkt = nyt produkt (); session.save (produkt); Produkt produkt2 = nyt produkt (); session.save (produkt2); assertThat (product2.getProdId ()). er EqualTo ("prod-2"); }

Her var den første værdi, der blev genereret ved hjælp af "prod" -præfikset, "prod-1" efterfulgt af "prod-2".

4. Kompositidentifikatorer

Udover de enkle identifikatorer, vi hidtil har set, giver Hibernate os også mulighed for at definere sammensatte identifikatorer.

Et sammensat id er repræsenteret af en primær nøgleklasse med en eller flere vedvarende attributter.

Den primære nøgleklasse skal opfylde flere betingelser:

  • det skal defineres ved hjælp af @EmbeddedId eller @IdClass kommentarer
  • det skal være offentligt, kan serieres og have en offentlig konstruktør uden argumenter
  • det skal gennemføres lige med() og hashCode () metoder

Klassens attributter kan være grundlæggende, sammensatte eller ManyToOne, mens man undgår samlinger og En til en egenskaber.

4.1. @EmbeddedId

For at definere et id ved hjælp af @EmbeddedId, først har vi brug for en primær nøgleklasse, der er kommenteret med @Embeddable:

@Embeddable public class OrderEntryPK implementerer Serializable {private long orderId; privat langt produktId; // standard konstruktør, getters, setter // er lig med () og hashCode ()}

Dernæst kan vi tilføje et id af typen OrderEntryPK til en enhed, der bruger @EmbeddedId:

@Entity offentlig klasse OrderEntry {@EmbeddedId privat OrderEntryPK entryId; // ...}

Lad os se, hvordan vi kan bruge denne type sammensat id til at indstille den primære nøgle til en enhed:

@Test offentlig ugyldig nårSaveCompositeIdEntity_thenOk () {OrderEntryPK entryPK = new OrderEntryPK (); entryPK.setOrderId (1L); entryPK.setProductId (30L); OrderEntry entry = new OrderEntry (); entry.setEntryId (entryPK); session.save (post); assertThat (entry.getEntryId (). getOrderId ()). er EqualTo (1L); }

Her er OrderEntry objekt har en OrderEntryPK primær id dannet af to attributter: Ordre ID og productId.

4.2. @IdClass

Det @IdClass kommentar svarer til @EmbeddedId, undtagen attributterne er defineret i hovedklassen ved hjælp af @Id for hver enkelt.

Klassen primærnøgle vil se ud som før.

Lad os omskrive OrderEntry eksempel med en @IdClass:

@Entity @IdClass (OrderEntryPK.class) offentlig klasse OrderEntry {@Id privat lang orderId; @Id privat langt produktId; // ...}

Derefter kan vi indstille id-værdierne direkte på OrderEntry objekt:

@Test offentlig ugyldig nårSaveIdClassEntity_thenOk () {OrderEntry entry = new OrderEntry (); entry.setOrderId (1L); entry.setProductId (30L); session.save (post); assertThat (entry.getOrderId ()). er EqualTo (1L); }

Bemærk, at den primære nøgleklasse også kan indeholde for begge typer sammensatte id'er @ManyToOne egenskaber.

Dvaletilstand tillader også at definere primære nøgler, der består af @ManyToOne foreninger kombineret med @Id kommentar. I dette tilfælde skal enhedsklassen også opfylde betingelserne for en primærnøgleklasse.

Ulempen ved denne metode er, at der ikke er nogen adskillelse mellem enhedsobjektet og identifikatoren.

5. Afledte identifikatorer

Afledte identifikatorer fås fra en enheds tilknytning ved hjælp af @MapsId kommentar.

Lad os først oprette en Brugerprofil enhed, der stammer sit id fra en en-til-en-forbindelse med Bruger enhed:

@Entity offentlig klasse UserProfile {@Id privat lang profilId; @OneToOne @MapsId privat brugerbruger; // ...}

Lad os derefter kontrollere, at en Brugerprofil instans har samme id som dets tilknyttede Bruger eksempel:

@Test offentlig ugyldig nårSaveDerivedIdEntity_thenOk () {Brugerbruger = ny bruger (); session.save (bruger); UserProfile-profil = ny UserProfile (); profile.setUser (bruger); session.save (profil); assertThat (profile.getProfileId ()). er EqualTo (user.getUserId ()); }

6. Konklusion

I denne artikel har vi set de mange måder, hvorpå vi kan definere identifikatorer i dvale.

Den fulde kildekode for eksemplerne kan findes på GitHub.