Pregled identifikatora u hibernaciji / JPA

1. Uvod

Identifikatori u hibernaciji predstavljaju primarni ključ entiteta. To podrazumijeva da su vrijednosti jedinstvene kako bi mogle identificirati određeni entitet, da nisu nule i da se neće mijenjati.

Hibernate pruža nekoliko različitih načina za definiranje identifikatora. U ovom ćemo članku pregledati svaku metodu mapiranja ID-ova entiteta pomoću knjižnice.

2. Jednostavni identifikatori

Najjednostavniji način definiranja identifikatora je pomoću @Iskaznica bilješka.

Jednostavni ID mapiraju se pomoću @Iskaznica na jedno svojstvo jednog od ovih tipova: Java primitivni i primitivni omot, Niz, datum, BigDecimal, BigInteger.

Pogledajmo brzi primjer definiranja entiteta s primarnim ključem tipa dugo:

@ Entitet javni razred Student {@Id private long studentId; // standardni konstruktor, getteri, postavljači}

3. Generirani identifikatori

Ako želimo da se vrijednost primarnog ključa generira automatski za nas, možemo dodati @GeneratedValue bilješka.

Ovdje se mogu koristiti 4 generacije: AUTO, IDENTITET, SEKVENCA, TABELA.

Ako vrijednost ne navedemo izričito, tip generacije po zadanom je AUTO.

3.1. AUTO Generacija

Ako koristimo zadani tip generacije, davatelj postojanosti odredit će vrijednosti na temelju vrste atributa primarnog ključa. Ova vrsta može biti numerička ili UUID.

Za numeričke vrijednosti, generiranje se temelji na generatoru niza ili tablice, dok UUID vrijednosti će koristiti UUIDGenerator.

Pogledajmo primjer mapiranja primarnog ključa entiteta pomoću strategije AUTO generiranja:

@ Entity javni razred Student {@Id @GeneratedValue private long studentId; // ...}

U ovom će slučaju vrijednosti primarnog ključa biti jedinstvene na razini baze podataka.

Zanimljiva značajka predstavljena u Hibernate 5 je UUIDGenerator. Da bismo to iskoristili, sve što trebamo učiniti je deklarirati id tipa UUID s @GeneratedValue napomena:

@ Tečaj javne klase Entity {@Id @GeneratedValue private UUID courseId; // ...}

Hibernate će generirati id oblika "8dd5f315-9788-4d00-87bb-10eed9eff566".

3.2. IDENTITET Generacija

Ova vrsta generacije oslanja se na IdentityGenerator koja očekuje vrijednosti generirane pomoću identitet stupac u bazi podataka, što znači da se automatski povećavaju.

Da bismo koristili ovu generacijsku vrstu, trebamo samo postaviti strategija parametar:

@ Entity javni razred Student {@Id @GeneratedValue (strategija = GenerationType.IDENTITY) private long studentId; // ...}

Treba napomenuti da generacija IDENTITY onemogućava serijska ažuriranja.

3.3. SLIJED Generacija

Da biste koristili id ​​zasnovan na sekvenci, Hibernate pruža SequenceStyleGenerator razred.

Ovaj generator koristi sekvence ako ih podržava naša baza podataka i prebacuje se na generiranje tablica ako nisu.

Da bismo prilagodili naziv sekvence, možemo koristiti @GenericGenerator bilješka s Strategija SequenceStyleGenerator:

Korisnik javne klase @Entity {@Id @GeneratedValue (generator = "generator-slijeda") @GenericGenerator (name = "generator-slijed", strategija = "org.hibernate.id.enhanced.SequenceStyleGenerator", parametri = {@Parameter ( ime = "ime_sljed", vrijednost = "korisnička_sljedica"), @Parameter (name = "Initial_value", value = "4"), @Parameter (name = "increment_size", value = "1")}) private long userId; // ...}

U ovom smo primjeru također postavili početnu vrijednost za slijed, što znači da će generiranje primarnog ključa započeti u 4.

SLIJED je vrsta generacije preporučena u hibernacijskoj dokumentaciji.

Generirane vrijednosti jedinstvene su po slijedu. Ako ne navedete naziv niza, Hibernate će ga ponovno upotrijebiti hibernacija_sljedica za različite vrste.

3.4. TABLICA Generacija

The TableGenerator koristi temeljnu tablicu baze podataka koja sadrži segmente vrijednosti generiranja identifikatora.

Prilagodimo naziv tablice pomoću @TableGenerator napomena:

Odjel javne klase @Entity {@Id @GeneratedValue (strategy = GenerationType.TABLE, generator = "generator-tablice") @TableGenerator (name = "generator-tablice", tablica = "dep_ids", pkColumnName = "seq_id", valueColumnName = "seq_value") private long depId; // ...}

U ovom primjeru možemo vidjeti da drugi atributi poput pkColumnName i valueColumnName također se može prilagoditi.

Nedostatak ove metode je što se ne skalira dobro i može negativno utjecati na performanse.

Da sumiramo, ove će četiri generacije rezultirati generiranjem sličnih vrijednosti, ali koriste različite mehanizme baze podataka.

3.5. Prilagođeni generator

Ako ne želimo koristiti nijednu izravnu strategiju, svoj korisnički generator možemo definirati primjenom IdentifierGenerator sučelje.

Stvorimo generator koji gradi identifikatore koji sadrže Niz prefiks i broj:

javna klasa MyGenerator implementira IdentifierGenerator, podesiv {prefiks privatnog niza; @Override public Serializable generiranje (SharedSessionContractImplementor session, Object obj) baca HibernateException {String query = String.format ("select% s from% s", session.getEntityPersister (obj.getClass (). GetName (), obj )PropertyIdentiP. ), obj.getClass (). getSimpleName ()); Stream ids = session.createQuery (query) .stream (); Long max = ids.map (o -> o.replace (prefiks + "-", "")) .mapToLong (Long :: parseLong) .max () .orElse (0L); vrati prefiks + "-" + (max + 1); } @Override javna void konfiguracija (vrsta tipa, svojstva svojstva, ServiceRegistry serviceRegistry) baca MappingException {prefix = properties.getProperty ("prefix"); }}

U ovom primjeru, nadjačavamo generirati() metoda iz IdentifierGenerator sučelje i prvo pronađite najveći broj iz postojećih primarnih ključeva obrasca prefiks-XX.

Zatim dodamo 1 na najveći pronađeni broj i dodamo prefiks svojstvo za dobivanje novo generirane vrijednosti id.

Naš razred također provodi Podesivo sučelje, tako da možemo postaviti prefiks vrijednost imovine u konfigurirati() metoda.

Dalje, dodajmo ovaj prilagođeni generator entitetu. Za ovo, možemo koristiti @GenericGenerator bilješka s a strategija parametar koji sadrži puno ime klase naše generatorske klase:

Proizvod javne klase @Entity {@Id @GeneratedValue (generator = "prod-generator") @GenericGenerator (name = "prod-generator", parametri = @Parameter (name = "prefix", value = "prod"), strategy = "com.baeldung.hibernate.pojo.generator.MyGenerator") private String prodId; // ...}

Također primijetite da smo parametar prefiksa postavili na "prod".

Pogledajmo brzi test JUnit za jasnije razumijevanje generiranih vrijednosti id:

@Test public void whenSaveCustomGeneratedId_thenOk () {Product product = new Product (); session.save (proizvod); Proizvod proizvoda2 = novi proizvod (); session.save (proizvod2); assertThat (product2.getProdId ()). isEqualTo ("prod-2"); }

Ovdje je prva vrijednost generirana pomoću prefiksa „prod“ bila „prod-1“, a zatim „prod-2“.

4. Sastavljeni identifikatori

Osim jednostavnih identifikatora koje smo do sada vidjeli, Hibernate nam omogućuje i definiranje složenih identifikatora.

Sastavljeni ID predstavlja klasa primarnog ključa s jednim ili više trajnih atributa.

Klasa primarnog ključa mora ispunjavati nekoliko uvjeta:

  • treba definirati pomoću @EmbeddedId ili @IdClass bilješke
  • trebao bi biti javan, serializirati i imati javni ne-arg konstruktor
  • treba provesti jednako () i hashCode () metode

Atributi klase mogu biti osnovni, složeni ili ManyToOne uz izbjegavanje kolekcija i Jedan na jedan atributi.

4.1. @EmbeddedId

Da biste definirali ID pomoću @EmbeddedId, prvo trebamo označenu klasu primarnog ključa @Embeddable:

@Embeddable javna klasa OrderEntryPK implementira Serializable {private long orderId; private long productId; // standardni konstruktor, getteri, postavljači // equals () i hashCode ()}

Dalje, možemo dodati id tipa OrderEntryPK entitetu pomoću @EmbeddedId:

@Entity javna klasa OrderEntry {@EmbeddedId private OrderEntryPK entryId; // ...}

Pogledajmo kako možemo koristiti ovu vrstu složenog ID-a za postavljanje primarnog ključa za entitet:

@Test public void whenSaveCompositeIdEntity_thenOk () {OrderEntryPK entryPK = new OrderEntryPK (); entryPK.setOrderId (1L); entryPK.setProductId (30L); OrderEntry entry = novi OrderEntry (); entry.setEntryId (entryPK); session.save (unos); assertThat (entry.getEntryId (). getOrderId ()). isEqualTo (1L); }

Ovdje OrderEntry objekt ima OrderEntryPK primarni id formiran od dva atributa: orderId i Identifikacijski broj proizvoda.

4.2. @IdClass

The @IdClass napomena slična je @EmbeddedId, osim što su atributi definirani u klasi glavnog entiteta pomoću @Iskaznica za svakoga.

Klasa primarnog ključa izgledat će isto kao i prije.

Prepišimo OrderEntry primjer s @IdClass:

@Entity @IdClass (OrderEntryPK.class) javna klasa OrderEntry {@Id private long orderId; @Id private long productId; // ...}

Tada možemo postaviti vrijednosti id izravno na OrderEntry objekt:

@Test public void whenSaveIdClassEntity_thenOk () {OrderEntry entry = new OrderEntry (); entry.setOrderId (1L); entry.setProductId (30L); session.save (unos); assertThat (entry.getOrderId ()). isEqualTo (1L); }

Imajte na umu da za obje vrste složenih ID-ova klasa primarnog ključa također može sadržavati @ManyToOne atributi.

Hibernate također omogućuje definiranje primarnih ključeva sastavljenih od @ManyToOne udruge u kombinaciji s @Iskaznica bilješka. U ovom bi slučaju klasa entiteta također trebala ispunjavati uvjete klase primarnog ključa.

Nedostatak ove metode je što se ne razdvaja entitetni objekt i identifikator.

5. Izvedeni identifikatori

Izvedeni identifikatori dobivaju se od udruženja entiteta pomoću @MapsId bilješka.

Prvo, izradimo a Korisnički profil entitet koji svoj identitet izvodi iz osobne povezanosti s Korisnik entitet:

@Entity javna klasa UserProfile {@Id private long profileId; @OneToOne @MapsId privatni korisnik; // ...}

Dalje, provjerimo da a Korisnički profil instanca ima isti id kao i pridruženi Korisnik primjer:

@Test public void whenSaveDerivedIdEntity_thenOk () {Korisnik korisnik = novi korisnik (); session.save (korisnik); Profil UserProfile = novi UserProfile (); profile.setUser (korisnik); session.save (profil); assertThat (profile.getProfileId ()). isEqualTo (user.getUserId ()); }

6. Zaključak

U ovom smo članku vidjeli više načina na koje možemo definirati identifikatore u hibernaciji.

Potpuni izvorni kod primjera može se naći na GitHubu.