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

Hibernate 6 EmbeddableInstantiator – Instantiate kan integreres på din måde

Embeddables er simple Java-objekter. De giver en nem måde at definere og gruppere et sæt attributter, der bliver en del af din enhed. Udviklere bruger dem ofte til at oprette genanvendelige kortoplysninger og håndtere dem ved hjælp af det samme stykke forretningskode.

Desværre krævede JPA-specifikationen og Hibernate indtil version 6.0.0, at din embeddable havde en standardkonstruktør. Dette kan være OK, hvis du henter en enhed fra databasen. Hibernate indstiller derefter automatisk alle attributter, før objektet leveres til din virksomhedskode. Men en standardkonstruktør er ikke altid en god idé. F.eks. hvis nogle af attributterne er obligatoriske, og du instanserer indlejrede elementer i din virksomhedskode eller frontend. I så fald ville en konstruktør, der sætter alle obligatoriske attributter, være meget bedre.

Siden Hibernate 6.0.0 kan du nemt definere, hvordan Hibernate instanserer og initialiserer din indlejrede. Du kan f.eks. bruge det til at fjerne kravet om en standardkonstruktør. Jeg vil vise dig, hvordan du gør det i denne artikel.

Hvad er en Embeddable, og hvordan man definerer den

En indlejret er en sammensætning af flere attributter og deres kortlægningsdefinitioner. Du kan bruge den som en attributtype i en eller flere enhedsklasser. Når du gør det, bliver alle attributter for det indlejrede en del af entitetsobjektet og følger dets livscyklus.

Her kan du se definitionen af ​​Adresse indlejres. Hvis du vil stole på Hibernates standardkortlægning for alle dens attributter, behøver du kun at annotere klassen med en @Embeddabl e anmærkning. Hvis du ikke allerede er bekendt med denne kortlægning, anbefaler jeg, at du tjekker Hibernates dokumentation eller ser det indlejrede foredrag om de avancerede dvalekurser, der er inkluderet i Persistence Hub.

@Embeddable
public class Address {

	private String street;
	private String city;
	private String postalCode;
	
    // getter and setter methods
}

Når du har defineret den indlejrbare, kan du bruge den som en attributtype i dine enhedsklasser og bruge den på samme måde som enhver anden enhedsattribut. I dette eksempel er alle attributter for adressen kan integreres, blive en del af Forfatteren entitet og bliv knyttet til forfatteren tabel.

@Entity
public class Author {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	
	@Version
	private int version;

	private String firstName;

	private String lastName;
	
	@Embedded
	private Address address;

    // getter and setter methods
}

Implementering af en EmbeddableInstantiator

Som standard vil Hibernate kalde standardkonstruktøren af ​​Adressen indlejres. Derefter bruger den refleksion til at indstille alle dens attributter, når du henter en Forfatter enhed fra databasen. Siden Hibernate 6 kan du tilpasse instansieringen af ​​den integrerede enhed ved at levere en EmbeddableInstantiator .

Lad os bruge dette til at undgå standardkonstruktøren af ​​adressen indlejres og brug en konstruktør, der sætter alle attributter i stedet for. Dette kræver 2 mindre ændringer af adressen klasse. Jeg skal tilføje den ekstra konstruktør, og jeg skal registrere min EmbeddableInstantiator . Du kan gøre det ved at annotere den integrerede klasse eller en entity-attribut af din indlejringstype med @EmbeddableInstantiator .

@Embeddable
@EmbeddableInstantiator(AddressInstantiator.class)
public class Address {

	private String street;
	private String city;
	private String postalCode;
	
    public Address(String street, String city, String postalCode) {
        this.street = street;
        this.city = city;
        this.postalCode = postalCode;
    }

    // getter methods
}

I det næste trin skal du implementere EmbeddableInstantiator interface. Dette er ikke kompliceret. Interfacet definerer kun 3 metoder. En metode kontrollerer, om et objekt er en forekomst af den håndterede, integrerede klasse. En anden kontrollerer, om et objekt er af samme klasse som den indlejrbare. Og den sidste metode instansierer det indlejrbare objekt.

Her kan du se AddressInstantiator klasse I refererede til i @EmbeddableInstantiator annotation i det forrige kodestykke.

public class AddressInstantiator implements EmbeddableInstantiator {

    Logger log = LogManager.getLogger(this.getClass().getName());

    public boolean isInstance(Object object, SessionFactoryImplementor sessionFactory) {
        return object instanceof Address;
    }

    public boolean isSameClass(Object object, SessionFactoryImplementor sessionFactory) {
        return object.getClass().equals( Address.class );
    }

    public Object instantiate(Supplier<Object[]> valuesAccess, SessionFactoryImplementor sessionFactory) {
        final Object[] values = valuesAccess.get();
        // valuesAccess contains attribute values in alphabetical order
        final String city = (String) values[0];
        final String postalCode = (String) values[1];
        final String street = (String) values[2];
        log.info("Instantiate Address embeddable for "+street+" "+postalCode+" "+city);
        return new Address( street, city, postalCode );
    }

}

Som du kan se i kodestykket, er instansen metoden indeholder koden til at instansiere og initialisere den indlejrede. Implementeringen af ​​denne metode er naturligvis applikationsspecifik.

Men der er én ting, jeg skal påpege. Metodeparameteren Supplier valuesAccess indeholder attributværdierne valgt fra databasen i alfabetisk rækkefølge efter deres attributnavne. I kodestykket kan du se, at jeg får de 3 værdier fra leverandøren . Jeg tildeler dem til navngivne variable og kaster hver af dem til String. Denne kortlægning kan forårsage vedligeholdelsesproblemer i fremtiden, men den gør i det mindste koden bedre forståelig. Hvis du har en bedre idé til dette, vil jeg elske at læse om det i kommentarerne.

Brug af en integrerbar med tilpasset EmbeddableInstantiator

Når du har defineret og registreret EmbeddableInstantiator , kan du bruge din indlejring på samme måde som enhver anden indlejrbar.

Du kan bruge den som en attributtype på en af ​​dine enhedsklasser og annotere attributten med @Embedded .

@Entity
public class Author {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	
	@Version
	private int version;

	private String firstName;

	private String lastName;
	
	@Embedded
	private Address address;

	...
}

Derefter kan du bruge attributten som enhver anden attribut i din virksomhedskode.

Author a = new Author();
a.setFirstName("firstName");
a.setLastName("lastName");

Address home = new Address("homeStreet", "homeCity", "12345");
a.setAddress(home);

em.persist(a);

Når jeg udfører denne kode, kan du se i log-outputtet, at Hibernate kortlagde alle attributter for Adressen kan integreres i Forfatteren tabellen og brugte AddressInstantiator for at instansiere adressen objekt.

Konklusion

Som du så i denne artikel, er EmbeddableInstantiator kontrakt introduceret i Hibernate 6 giver dig mere fleksibilitet, når du arbejder med embeddables. Det giver dig fuld kontrol over instansieringen og initialiseringen af ​​dine indlejrbare objekter. Du kan bruge dette til forskellige ting. Du kan udføre yderligere forretningslogik eller transformere eller beregne attributværdier, før du instansierer det indlejrede. Eller du kan undgå standardkonstruktøren og kalde en konstruktør, der fuldt ud initialiserer dit indlejrbare objekt i stedet.


Java tag