Spring Data Composable Repositories
1. Introduktion
Når du modellerer et virkeligt system eller proces, er DDD-stil repositories en god mulighed. Til netop dette formål kan vi bruge Spring Data JPA som vores abstraktionslag for dataadgang.
Hvis du er ny på dette koncept, skal du tjekke denne introduktionsvejledning for at hjælpe dig med at komme op i hastighed.
I denne vejledning fokuserer vi på konceptet med at oprette brugerdefinerede såvel som komponerbare opbevaringssteder, der oprettes ved hjælp af mindre opbevaringssteder kaldet fragmenter.
2. Maven-afhængigheder
Muligheden for at oprette komponerbare arkiver er tilgængelig startende med forår 5.
Lad os tilføje den krævede afhængighed af Spring Data JPA:
org.springframework.data spring-data-jpa 2.2.2.RELEASE
Vi bliver også nødt til at oprette en datakilde, for at vores dataadgangslag kan fungere. Det er en god idé at oprette en hukommelsesdatabase som H2 til udvikling og hurtig test.
3. Baggrund
3.1. Dvale som JPA-implementering
Spring Data JPA bruger som standard dvale som JPA-implementering. Vi kan let forveksle det ene med det andet eller sammenligne dem, men de tjener forskellige formål.
Spring Data JPA er det dataadgangsabstraktionslag, hvorunder vi kan bruge enhver implementering. Vi kunne for eksempel slukke Dvaletilstand til fordel for EclipseLink.
3.2. Standardlagre
I mange tilfælde behøver vi ikke selv skrive forespørgsler.
I stedet behøver vi kun at oprette grænseflader, som igen udvider de generiske Spring-datalagergrænseflader:
offentlig grænseflade LocationRepository udvider JpaRepository {}
Og dette i sig selv ville give os mulighed for at udføre fælles operationer - CRUD, personsøgning og sortering - på Beliggenhed objekt, der har en primær nøgle af typen Lang.
Desuden er Spring Data JPA udstyret med en forespørgselsbygningsmekanisme, der giver mulighed for at generere forespørgsler på vores vegne ved hjælp af metodenavnkonventioner:
offentlig grænseflade StoreRepository udvider JpaRepository {List findStoreByLocationId (Long locationId); }
3.3. Brugerdefinerede arkiver
Hvis det er nødvendigt, kan vi berige vores modelarkiv ved at skrive en fragmentgrænseflade og implementere den ønskede funktionalitet. Dette kan derefter injiceres i vores eget JPA-arkiv.
For eksempel beriger vi her vores ItemTypeRepository ved at udvide et fragmentlager:
offentlig grænseflade ItemTypeRepository udvider JpaRepository, CustomItemTypeRepository {}
Her CustomItemTypeRepository er en anden grænseflade:
offentlig grænseflade CustomItemTypeRepository {ugyldig deleteCustomById (ItemType-enhed); }
Dens implementering kan være et arkiv af enhver art, ikke kun JPA:
offentlig klasse CustomItemTypeRepositoryImpl implementerer CustomItemTypeRepository {@Autowired private EntityManager entityManager; @ Overstyr offentlig tomrum deleteCustomById (ItemType itemType) {entityManager.remove (itemType); }}
Vi skal bare sørge for, at det har postfixet Impl. Vi kan dog indstille et tilpasset postfix ved hjælp af følgende XML-konfiguration:
eller ved hjælp af denne kommentar:
@EnableJpaRepositories (basePackages = "com.baeldung.repository", repositoryImplementationPostfix = "CustomImpl")
4. Komponering af arkiver ved brug af flere fragmenter
Indtil for nogle få udgivelser siden kunne vi kun udvide vores lagerinterfaces ved hjælp af en enkelt brugerdefineret implementering. Dette var en begrænsning, på grund af hvilken vi skulle bringe al relateret funktionalitet ind i et enkelt objekt.
Det er overflødigt at sige, at for større projekter med komplekse domænemodeller fører dette til oppustede klasser.
Nu med forår 5 har vi muligheden for at berige vores JPA-arkiv med flere fragmentlagre. Igen forbliver kravet, at vi har disse fragmenter som interface-implementeringspar.
Lad os oprette to fragmenter for at demonstrere dette:
offentlig grænseflade CustomItemTypeRepository {void deleteCustom (ItemType entity); ugyldigt findThenDelete (langt id); } offentlig grænseflade CustomItemRepository {Item findItemById (Lang id); ugyldig deleteCustom (vareenhed); ugyldigt findThenDelete (langt id); }
Selvfølgelig skulle vi skrive deres implementeringer. Men i stedet for at tilslutte disse brugerdefinerede opbevaringssteder - med relaterede funktionaliteter - i deres egne JPA-opbevaringssteder, kan vi udvide funktionaliteten i et enkelt JPA-arkiv:
offentlig grænseflade ItemTypeRepository udvider JpaRepository, CustomItemTypeRepository, CustomItemRepository {}
Nu ville vi have al den sammenkædede funktionalitet i et enkelt arkiv.
5. Håndtering af tvetydighed
Da vi arver fra flere arkiver, kan vi have problemer med at finde ud af, hvilke af vores implementeringer der ville blive brugt i tilfælde af sammenstød. For eksempel, i vores eksempel, har begge fragmentlagre en metode, findThenDelete (), med samme underskrift.
I dette scenarie rækkefølgen af erklæringen af grænsefladerne bruges til at løse tvetydigheden. Derfor, i vores tilfælde, metoden inde CustomItemTypeRepository vil blive brugt, da det er erklæret først.
Vi kan teste dette ved hjælp af denne test case:
@Test offentlig ugyldighed givenItemAndItemTypeWhenDeleteThenItemTypeDeleted () {Valgfri itemType = sammensatRepository.findById (1L); assertTrue (itemType.isPresent ()); Item item = wroteRepository.findItemById (2L); assertNotNull (vare); wroteRepository.findThenDelete (1L); Valgfri sameItemType = komponeretRepository.findById (1L); assertFalse (sameItemType.isPresent ()); Vare sameItem = sammensatRepository.findItemById (2L); assertNotNull (sameItem); }
6. Konklusion
I denne artikel kiggede vi på de forskellige måder, hvorpå vi kan bruge Spring Data JPA repositories. Vi så, at Spring gør det nemt at udføre databasehandlinger på vores domæneobjekter uden at skrive meget kode eller endda SQL-forespørgsler.
Denne support kan tilpasses betydeligt ved brug af komponerbare arkiver.
Kodestykkerne fra denne artikel er tilgængelige som et Maven-projekt her på GitHub.