Introduktion til Jinq med forår

1. Introduktion

Jinq giver en intuitiv og praktisk tilgang til forespørgsel på databaser i Java. I denne vejledning udforsker vi hvordan man konfigurerer et forårsprojekt til at bruge Jinq og nogle af dens funktioner illustreret med enkle eksempler.

2. Maven-afhængigheder

Vi bliver nødt til at tilføje Jinq-afhængigheden i pom.xml fil:

 org.jinq jinq-jpa 1.8.22 

Til foråret tilføjer vi foråret ORM-afhængighed i pom.xml fil:

 org.springframework spring-orm 5.2.5.RELEASE 

Endelig til test bruger vi en H2-hukommelsesdatabase, så lad os også tilføje denne afhængighed sammen med spring-boot-starter-data-jpa til pom.xml-filen:

 com.h2database h2 1.4.200 org.springframework.boot spring-boot-starter-data-jpa 2.2.6.RELEASE 

3. Forståelse af Jinq

Jinq hjælper os med at skrive lettere og mere læsbare databaseforespørgsler ved at udsætte en flydende API, der er internt baseret på Java Stream API.

Lad os se et eksempel, hvor vi filtrerer biler efter model:

jinqDataProvider.streamAll (entityManager, Car.class) .where (c -> c.getModel (). er lig med (model)) .toList ();

Jinq oversætter ovenstående kodestykke til en SQL-forespørgsel på en effektiv måde, så den sidste forespørgsel i dette eksempel ville være:

vælg c. * fra bil c hvor c.model =?

Da vi ikke bruger almindelig tekst til at skrive forespørgsler og i stedet bruger en typesikker API, er denne tilgang mindre tilbøjelig til fejl.

Derudover sigter Jinq mod at tillade hurtigere udvikling ved hjælp af almindelige, letlæselige udtryk.

Ikke desto mindre har det nogle begrænsninger i antallet af typer og operationer, vi kan bruge, som vi vil se næste.

3.1. Begrænsninger

Jinq understøtter kun de grundlæggende typer i JPA og en konkret liste over SQL-funktioner. Det fungerer ved at oversætte lambda-operationerne til en native SQL-forespørgsel ved at kortlægge alle objekter og metoder til en JPA-datatype og en SQL-funktion.

Derfor kan vi ikke forvente, at værktøjet oversætter enhver brugerdefineret type eller alle metoder af en type.

3.2. Understøttede datatyper

Lad os se de understøttede datatyper og understøttede metoder:

  • Snorlige med(), sammenligne med() kun metoder
  • Primitive datatyper - aritmetiske operationer
  • Enums og tilpassede klasser - understøtter kun == og! = operationer
  • java.util.Collection - indeholder()
  • Dato API - lige med(), Før(), efter() kun metoder

Bemærk: Hvis vi ønsker at tilpasse konverteringen fra et Java-objekt til et databaseobjekt, skal vi registrere vores konkrete implementering af en AttributeConverter i Jinq.

4. Integrering af Jinq med foråret

Jinq har brug for en EntityManager eksempel for at få vedholdenhedskonteksten. I denne vejledning introducerer vi en enkel tilgang med Spring for at få Jinq til at arbejde med EntityManager leveret af dvale.

4.1. Lagringsgrænseflade

Spring bruger begrebet arkiver til at styre enheder. Lad os se på vores CarRepository interface, hvor vi har en metode til at hente en Bil for en given model:

offentlig grænseflade CarRepository {Valgfri findByModel (strengmodel); }

4.2. Abstrakt basislager

Næste, vi har brug for et basislager at levere alle Jinq-mulighederne:

offentlig abstrakt klasse BaseJinqRepositoryImpl {@Autowired private JinqJPAStreamProvider jinqDataProvider; @PersistenceContext private EntityManager entityManager; beskyttet abstrakt Class entityType (); offentlig JPAJinqStream-stream () {return streamOf (entityType ()); } beskyttet JPAJinqStream streamOf (Class clazz) {return jinqDataProvider.streamAll (entityManager, clazz); }}

4.3. Implementering af lageret

Nu er alt, hvad vi har brug for til Jinq, et EntityManager forekomst og enhedstypeklassen.

Lad os se Bil repository implementering ved hjælp af vores Jinq base repository, som vi netop definerede:

@Repository public class CarRepositoryImpl udvider BaseJinqRepositoryImpl implementerer CarRepository {@Override public Valgfri findByModel (String model) {return stream () .where (c -> c.getModel (). Equals (model)) .findFirst (); } @ Override beskyttet Class entityType () {returner Car.class; }}

4.4. Ledningsføring af JinqJPAStreamProvider

For at binde kablet JinqJPAStreamProvider eksempel, vi vil tilføj Jinq-udbyderkonfigurationen:

@Configuration offentlig klasse JinqProviderConfiguration {@Bean @Autowired JinqJPAStreamProvider jinqProvider (EntityManagerFactory emf) {returner nye JinqJPAStreamProvider (emf); }}

4.5. Konfiguration af forårsprogrammet

Det sidste trin er at konfigurer vores Spring-applikation ved hjælp af Dvaletilstand og vores Jinq-konfiguration. Se vores som en reference application.properties fil, hvor vi bruger en H2-hukommelse i hukommelsen som database:

spring.datasource.url = jdbc: h2: ~ / jinq spring.datasource.username = sa spring.datasource.password = spring.jpa.hibernate.ddl-auto = create-drop

5. Forespørgselsguide

Jinq giver mange intuitive muligheder for at tilpasse den endelige SQL-forespørgsel med vælg, hvor,slutter sig til og meget mere. Bemærk, at disse har de samme begrænsninger, som vi allerede har introduceret ovenfor.

5.1. Hvor

Det hvor klausul tillader anvendelse af flere filtre til en dataindsamling.

I det næste eksempel vil vi filtrere biler efter model og beskrivelse:

stream (). hvor (c -> c.getModel (). er lig med (model) && c.getDescription (). indeholder (desc)) .toList ();

Og dette er den SQL, som Jinq oversætter:

vælg c.model, c.beskrivelse fra bil c hvor c.model =? og find (?, c.beskrivelse)> 0

5.2. Vælg

Hvis vi kun vil hente et par kolonner / felter fra databasen, skal vi bruge Vælg klausul.

For at kortlægge flere værdier giver Jinq et antal Tuple klasser med op til otte værdier:

stream () .select (c -> new Tuple3 (c.getModel (), c.getYear (), c.getEngine ())). toList ()

Og den oversatte SQL:

vælg c.model, c.år, c.motor fra bil c

5.3. Tilslutter sig

Jinq er i stand til at løse en-til-en og mange-til-en relationer hvis enhederne er korrekt forbundet.

For eksempel, hvis vi tilføjer producentens enhed i Bil:

@Entity (name = "CAR") offentlig klasse bil {// ... @OneToOne @JoinColumn (name = "name") offentlig Producent getManufacturer () {returproducent; }}

Og Fabrikant enhed med listen over Bils:

@Entity (name = "MANUFACTURER") offentlig klasse Producent {// ... @OneToMany (mappedBy = "model") offentlig Liste getCars () {returbiler; }}

Vi er nu i stand til at få Fabrikant for en given model:

Valgfri producent = stream (). Hvor (c -> c.getModel (). Er lig med (model)) .select (c -> c.getManufacturer ()) .findFirst ();

Som forventet, Jinq bruger en indre SQL-klausul i dette scenarie:

vælg m.navn, m.by fra bil c indre sammenføjningsproducent m på c.navn = m.navn hvor c.model =?

Hvis vi har brug for at have mere kontrol over tilslutte klausuler for at implementere mere komplekse relationer over enhederne, som et forhold mellem mange og mange, kan vi bruge tilslutte metode:

Liste list = streamOf (Manufacturer.class) .join (m -> JinqStream.from (m.getCars ())) .toList ()

Endelig kunne vi bruge en venstre ydre join SQL-klausul ved at bruge leftOuterJoin metode i stedet for tilslutte metode.

5.4. Aggregationer

Alle de eksempler, vi hidtil har introduceret, bruger enten toListe eller den findFirst metoder - for at returnere det endelige resultat af vores forespørgsel i Jinq.

Udover disse metoder, vi har også adgang til andre metoder til at samle resultater.

Lad os for eksempel bruge tælle metode til at få det samlede antal biler til en konkret model i vores database:

lang total = stream (). hvor (c -> c.getModel (). er lig med (model)). count ()

Og den endelige SQL bruger tælle SQL-metode som forventet:

vælg antal (c.model) fra bil c hvor c.model =?

Jinq leverer også aggregeringsmetoder som f.eks sum, gennemsnit, min, maks. og mulighed for at kombinere forskellige sammenlægninger.

5.5. Paginering

Hvis vi vil læse data i batches, kan vi bruge begrænse og springe metoder.

Lad os se et eksempel, hvor vi vil springe de første 10 biler over og kun få 20 varer:

stream () .skip (10) .limit (20) .toList ()

Og den genererede SQL er:

vælg c. * fra bil c grænse? forskudt?

6. Konklusion

Sådan der. I denne artikel har vi set en tilgang til opsætning af en Spring-applikation med Jinq ved hjælp af dvale (minimalt).

Vi har også kort undersøgt Jinqs fordele og nogle af dens hovedfunktioner.

Som altid kan kilderne findes på GitHub.