Spring Data Composable Repositories

1. Inleiding

Bij het modelleren van een realistisch systeem of proces, zijn opslagplaatsen in DDD-stijl (Domain-Driven Design) een goede optie. Voor dit doel kunnen we Spring Data JPA gebruiken als onze abstractielaag voor gegevenstoegang.

Als je nieuw bent bij dit concept, bekijk dan deze inleidende tutorial om je op weg te helpen.

In deze zelfstudie zullen we ons concentreren op het concept van het maken van zowel aangepaste als samenstelbare opslagplaatsen die zijn gemaakt met behulp van kleinere opslagplaatsen die fragmenten worden genoemd.

2. Maven afhankelijkheden

De optie om composable repositories te maken is beschikbaar vanaf Spring 5.

Laten we de vereiste afhankelijkheid voor Spring Data JPA toevoegen:

 org.springframework.data spring-data-jpa 2.2.2.RELEASE 

We zouden ook een gegevensbron moeten instellen om onze gegevenstoegangslaag te laten werken. Het is een goed idee om een ​​in-memory database zoals H2 op te zetten voor ontwikkeling en snelle tests.

3. Achtergrond

3.1. Slaapstand als JPA-implementatie

Spring Data JPA gebruikt standaard Hibernate als de JPA-implementatie. We kunnen de een gemakkelijk met de ander verwarren of ze vergelijken, maar ze dienen verschillende doeleinden.

Spring Data JPA is de abstractielaag voor gegevenstoegang waaronder we elke implementatie kunnen gebruiken. We zouden bijvoorbeeld de slaapstand kunnen uitschakelen ten gunste van EclipseLink.

3.2. Standaard opslagplaatsen

In veel gevallen hoeven we zelf geen vragen te stellen.

In plaats daarvan hoeven we alleen interfaces te maken die op hun beurt de generieke Spring-gegevensrepository-interfaces uitbreiden:

openbare interface LocationRepository breidt JpaRepository {} uit

En dit op zichzelf zou ons in staat stellen om algemene bewerkingen uit te voeren - CRUD, paging en sortering - op het Plaats object dat een primaire sleutel van het type heeft Lang.

Bovendien is Spring Data JPA uitgerust met een mechanisme voor het maken van query's dat de mogelijkheid biedt om namens ons query's te genereren met behulp van de naamconventies van methoden:

openbare interface StoreRepository breidt JpaRepository {List findStoreByLocationId (Long locationId) uit; }

3.3. Aangepaste opslagplaatsen

Indien gewenst kunnen we verrijk onze modelrepository door een fragmentinterface te schrijven en de gewenste functionaliteit te implementeren. Dit kan vervolgens worden geïnjecteerd in onze eigen JPA-repository.

Hier verrijken we bijvoorbeeld onze ItemTypeRepository door een fragmentrepository uit te breiden:

openbare interface ItemTypeRepository breidt JpaRepository, CustomItemTypeRepository {} uit

Hier CustomItemTypeRepository is een andere interface:

openbare interface CustomItemTypeRepository {void deleteCustomById (ItemType entiteit); }

De implementatie ervan kan een opslagplaats zijn van welke aard dan ook, niet alleen JPA:

openbare klasse CustomItemTypeRepositoryImpl implementeert CustomItemTypeRepository {@Autowired private EntityManager entityManager; @Override public void deleteCustomById (ItemType itemType) {entityManager.remove (itemType); }}

We moeten er alleen voor zorgen dat het de postfix heeft Impl. We kunnen echter een aangepaste postfix instellen door de volgende XML-configuratie te gebruiken:

of door deze annotatie te gebruiken:

@EnableJpaRepositories (basePackages = "com.baeldung.repository", repositoryImplementationPostfix = "CustomImpl")

4. Repositories samenstellen met behulp van meerdere fragmenten

Tot een paar releases geleden konden we onze repository-interfaces alleen uitbreiden met een enkele aangepaste implementatie. Dit was een beperking waardoor we alle gerelateerde functionaliteit in één object moesten samenbrengen.

Onnodig te zeggen dat dit bij grotere projecten met complexe domeinmodellen tot opgeblazen klassen leidde.

Nu met Spring 5 hebben we de optie om verrijk onze JPA-repository met meerdere fragmentrepositories. Nogmaals, de vereiste blijft dat we deze fragmenten hebben als interface-implementatie-paren.

Om dit te demonstreren, maken we twee fragmenten:

openbare interface CustomItemTypeRepository {void deleteCustom (ItemType entiteit); leegte findThenDelete (lange id); } openbare interface CustomItemRepository {Item findItemById (lange id); void deleteCustom (Item entiteit); leegte findThenDelete (lange id); }

Natuurlijk zouden we hun implementaties moeten schrijven. Maar in plaats van deze aangepaste repositories - met gerelateerde functionaliteiten - in hun eigen JPA-repositories te pluggen, kunnen we de functionaliteit van een enkele JPA-repository uitbreiden:

openbare interface ItemTypeRepository breidt JpaRepository, CustomItemTypeRepository, CustomItemRepository {} uit

Nu zouden we alle gekoppelde functionaliteit in één enkele repository hebben.

5. Omgaan met ambiguïteit

Omdat we erven van meerdere repositories, kunnen we moeite hebben om erachter te komen welke van onze implementaties zouden worden gebruikt in geval van een botsing. In ons voorbeeld hebben bijvoorbeeld beide fragmentrepository's een methode, findThenDelete (), met dezelfde handtekening.

In dit scenario, de volgorde van de aangifte van de interfaces wordt gebruikt om de dubbelzinnigheid op te lossen. Bijgevolg, in ons geval, de methode binnen CustomItemTypeRepository wordt gebruikt omdat het als eerste wordt gedeclareerd.

We kunnen dit testen met behulp van deze testcase:

@Test openbare ongeldig gegevenItemAndItemTypeWhenDeleteThenItemTypeDeleted () {Optioneel itemType = composRepository.findById (1L); assertTrue (itemType.isPresent ()); Item item = composRepository.findItemById (2L); assertNotNull (item); samengesteldRepository.findThenDelete (1L); Optioneel sameItemType = composRepository.findById (1L); assertFalse (sameItemType.isPresent ()); Item sameItem = composRepository.findItemById (2L); assertNotNull (sameItem); }

6. Conclusie

In dit artikel hebben we de verschillende manieren bekeken waarop we Spring Data JPA-opslagplaatsen kunnen gebruiken. We zagen dat Spring het eenvoudig maakt om databasebewerkingen uit te voeren op onze domeinobjecten zonder veel code of zelfs SQL-query's te schrijven.

Deze ondersteuning is aanzienlijk aanpasbaar door het gebruik van composable repositories.

De codefragmenten uit dit artikel zijn beschikbaar als een Maven-project hier op GitHub.