Spring Data JPA- und Named Entity-Diagramme

1. Übersicht

Einfach ausgedrückt sind Entitätsdiagramme eine weitere Möglichkeit, eine Abfrage in JPA 2.1 zu beschreiben. Wir können sie verwenden, um leistungsfähigere Abfragen zu formulieren.

In diesem Tutorial lernen wir anhand eines einfachen Beispiels, wie Entity Graphs mit Spring Data JPA implementiert werden.

2. Die Entitäten

Lassen Sie uns zunächst ein Modell namens Item erstellen, das mehrere Merkmale aufweist:

@Entity public class Item { @Id private Long id; private String name; @OneToMany(mappedBy = "item") private List characteristics = new ArrayList(); // getters and setters }

Definieren wir nun die C- charakteristische Entität:

@Entity public class Characteristic { @Id private Long id; private String type; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn private Item item; //Getters and Setters }

Wie wir im Code sehen können, werden sowohl das Merkmalsfeld in der Elemententität als auch das Elementfeld in der Merkmalentität mithilfe des Abrufparameters träge geladen . Also, unser Ziel hier ist es, sich eifrig zur Laufzeit zu laden.

3. Die Entitätsdiagramme

In Spring Data JPA können wir ein Entitätsdiagramm mithilfe einer Kombination aus Annotationen @NamedEntityGraph und @EntityGraph definieren . Sie können Ad-hoc-Entitätsdiagramme auch nur mit dem Attribut attributePaths der Annotation @EntityGraph definieren .

Mal sehen, wie es geht.

3.1. Mit @NamedEntityGraph

Erstens können wir die @ NamedEntityGraph- Annotation von JPA direkt auf unserer Item- Entität verwenden:

@Entity @NamedEntityGraph(name = "Item.characteristics", attributeNodes = @NamedAttributeNode("characteristics") ) public class Item { //... }

Anschließend können wir die Annotation @EntityGraph an eine unserer Repository-Methoden anhängen :

public interface ItemRepository extends JpaRepository { @EntityGraph(value = "Item.characteristics") Item findByName(String name); }

Wie der Code zeigt, haben wir den Namen des Entitätsdiagramms, das wir zuvor für die Item- Entität erstellt haben, an die Annotation @EntityGraph übergeben . Wenn wir die Methode aufrufen, ist dies die Abfrage, die Spring Data verwendet.

Der Standardwert des Typarguments der Annotation @EntityGraph ist EntityGraphType.FETCH . Wenn wir dies verwenden, wendet das Spring Data-Modul die FetchType.EAGER- Strategie auf die angegebenen Attributknoten an. Für andere wird die Strategie FetchType.LAZY angewendet.

In unserem Fall wird die Eigenschaft properties also eifrig geladen, obwohl die Standardabrufstrategie der Annotation @OneToMany faul ist.

Ein Haken dabei ist , dass , wenn die definierte Abrufstrategie ist EAGER, dann können wir nicht sein Verhalten ändern LAZY . Dies ist beabsichtigt, da die nachfolgenden Operationen möglicherweise die eifrig abgerufenen Daten zu einem späteren Zeitpunkt während der Ausführung benötigen.

3.2. Ohne @NamedEntityGraph

Oder wir können mit attributePaths auch ein Ad-hoc-Entitätsdiagramm definieren .

Fügen wir unserem CharacteristicsRepository ein Ad-hoc-Entitätsdiagramm hinzu, das das übergeordnete Element eifrig lädt :

public interface CharacteristicsRepository extends JpaRepository { @EntityGraph(attributePaths = {"item"}) Characteristic findByType(String type); }

Dadurch wird die item- Eigenschaft der Characteristic- Entität eifrig geladen , obwohl unsere Entität eine Strategie zum verzögerten Laden für diese Eigenschaft deklariert.

Dies ist praktisch, da wir das Entitätsdiagramm inline definieren können, anstatt auf ein vorhandenes benanntes Entitätsdiagramm zu verweisen.

4. Testfall

Nachdem wir unsere Entitätsdiagramme definiert haben, erstellen wir einen Testfall, um dies zu überprüfen:

@DataJpaTest @RunWith(SpringRunner.class) @Sql(scripts = "/entitygraph-data.sql") public class EntityGraphIntegrationTest { @Autowired private ItemRepository itemRepo; @Autowired private CharacteristicsRepository characteristicsRepo; @Test public void givenEntityGraph_whenCalled_shouldRetrunDefinedFields() { Item item = itemRepo.findByName("Table"); assertThat(item.getId()).isEqualTo(1L); } @Test public void givenAdhocEntityGraph_whenCalled_shouldRetrunDefinedFields() { Characteristic characteristic = characteristicsRepo.findByType("Rigid"); assertThat(characteristic.getId()).isEqualTo(1L); } }

Der erste Test verwendet das Entitätsdiagramm, das mit der Annotation @NamedEntityGraph definiert wurde .

Sehen wir uns das von Hibernate generierte SQL an:

select item0_.id as id1_10_0_, characteri1_.id as id1_4_1_, item0_.name as name2_10_0_, characteri1_.item_id as item_id3_4_1_, characteri1_.type as type2_4_1_, characteri1_.item_id as item_id3_4_0__, characteri1_.id as id1_4_0__ from item item0_ left outer join characteristic characteri1_ on item0_.id=characteri1_.item_id where item0_.name=?

Entfernen Sie zum Vergleich die Annotation @EntityGraph aus dem Repository und überprüfen Sie die Abfrage:

select item0_.id as id1_10_, item0_.name as name2_10_ from item item0_ where item0_.name=?

Anhand dieser Abfragen können wir deutlich erkennen, dass die Abfrage, die ohne die Annotation @EntityGraph generiert wurde, keine Eigenschaften der charakteristischen Entität lädt . Infolgedessen wird nur die Item- Entität geladen .

Zuletzt vergleichen wir die Hibernate-Abfragen des zweiten Tests mit der Annotation @EntityGraph :

select characteri0_.id as id1_4_0_, item1_.id as id1_10_1_, characteri0_.item_id as item_id3_4_0_, characteri0_.type as type2_4_0_, item1_.name as name2_10_1_ from characteristic characteri0_ left outer join item item1_ on characteri0_.item_id=item1_.id where characteri0_.type=?

Und die Abfrage ohne die Annotation @EntityGraph :

select characteri0_.id as id1_4_, characteri0_.item_id as item_id3_4_, characteri0_.type as type2_4_ from characteristic characteri0_ where characteri0_.type=?

5. Schlussfolgerung

In diesem Tutorial haben wir gelernt, wie Sie JPA-Entitätsdiagramme in Spring Data verwenden. Mit Spring Data können wir mehrere Repository-Methoden erstellen, die mit verschiedenen Entitätsdiagrammen verknüpft sind .

Die Beispiele für diesen Artikel sind auf GitHub verfügbar.