JPA de dados da primavera e gráficos de entidades nomeadas
1. Visão geral
Simply put, Entity Graphs are another way to describe a query in JPA 2.1. Podemos usá-los para formular consultas de melhor desempenho.
Neste tutorial, vamos aprender como implementar gráficos de entidade comSpring Data JPA por meio de um exemplo simples.
2. As Entidades
Primeiro, vamos criar um modelo chamadoItem que tem várias características:
@Entity
public class Item {
@Id
private Long id;
private String name;
@OneToMany(mappedBy = "item")
private List characteristics = new ArrayList<>();
// getters and setters
}
Agora vamos definir a entidade Characteristic:
@Entity
public class Characteristic {
@Id
private Long id;
private String type;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private Item item;
//Getters and Setters
}
Como podemos ver no código, tanto o campocharacteristics na entidadeItem e o campoitem na entidadeCharacteristic são carregados lentamente usando ofetch parâmetro. Então,our goal here is to load them eagerly at runtime.
3. Os Gráficos de Entidade
No Spring Data JPA, podemos definir um gráfico de entidade usando umcombination of @NamedEntityGraph and @EntityGraph annotations. Ou também podemos definir gráficos de entidade ad-hoc com apenas oattributePaths argument of the @EntityGraph annotation.
Vamos ver como isso pode ser feito.
3.1. Com@NamedEntityGraph
Primeiro, podemos usar a anotação@NamedEntityGraph do JPA diretamente em nossa entidadeItem:
@Entity
@NamedEntityGraph(name = "Item.characteristics",
attributeNodes = @NamedAttributeNode("characteristics")
)
public class Item {
//...
}
E então, podemos anexar a anotação@EntityGraph a um dos nossos métodos de repositório:
public interface ItemRepository extends JpaRepository- {
@EntityGraph(value = "Item.characteristics")
Item findByName(String name);
}
Como mostra o código, passamos o nome do gráfico da entidade,which we’ve created earlier on the Item entity, para a anotação@EntityGraph. Quando chamamos o método, essa é a consulta que Spring Data usará.
The default value of the type argument of the @EntityGraph annotation is EntityGraphType.FETCH. Quando usamos isso, o módulo Spring Data aplicará a estratégiaFetchType.EAGER nos nós de atributo especificados. E para outros, a estratégiaFetchType.LAZY será aplicada.
Portanto, em nosso caso, a propriedadecharacteristics será carregada avidamente, embora a estratégia de busca padrão da anotação@OneToMany seja lenta.
Um problema aqui é queif the defined fetch strategy is EAGER, then we cannot change its behavior to*LAZY*. Isso ocorre por design, uma vez que as operações subsequentes podem precisar dos dados buscados avidamente em um ponto posterior durante a execução.
3.2. Sem@NamedEntityGraph
Or, we can define an ad-hoc entity graph, too, withattributePaths.
Vamos adicionar um gráfico de entidade ad-hoc ao nossoCharacteristicsRepository que carrega avidamente seu paiItem:
public interface CharacteristicsRepository
extends JpaRepository {
@EntityGraph(attributePaths = {"item"})
Characteristic findByType(String type);
}
Isso carregará a propriedadeitem da entidadeCharacteristic avidamente,even though our entity declares a lazy-loading strategy for this property.
Isso é útil, pois podemos definir o gráfico de entidade em linha, em vez de nos referir a um gráfico de entidade nomeado existente.
4. Caso de teste
Agora que definimos nossos gráficos de entidade, vamos criar um caso de teste para verificá-lo:
@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);
}
}
O primeiro teste usará o gráfico de entidade definido usando a anotação@NamedEntityGraph.
Vamos ver o SQL gerado pelo Hibernate:
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=?
Para comparação, vamos remover a anotação@EntityGraph do repositório e inspecionar a consulta:
select
item0_.id as id1_10_,
item0_.name as name2_10_
from
item item0_
where
item0_.name=?
A partir dessas consultas, podemos observar claramente que a consulta gerada sem a anotação@EntityGraphis not loading any properties of Characteristic entity. Como resultado, carrega apenas a entidadeItem.
Por último, vamos comparar as consultas do Hibernate do segundo teste com a anotação@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=?
E a consulta sem a anotação@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. Conclusão
Neste tutorial, aprendemos como usar JPA Entity Graphs em Spring Data. Com Spring Data,we can create multiple repository methods that are linked to different entity graphs.
Os exemplos para este artigo estão disponíveisover on GitHub.