Reputation: 107
I'm trying the EntityGraph in a simple scenario of springdata jpa:
The idea is just to get an entity with its id field and omit another field called name.
This is the entity to be retrieved:
Entity
@NamedEntityGraph(name = "Region.id",
attributeNodes = @NamedAttributeNode("id"))
public class Region {
@Id
public String id;
public String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The repository:
public interface RegionRepository extends JpaRepository<Region, String>{
@EntityGraph(value = "Region.id")
Region findByRegionId(String name);
}
And a Service:
@Service
public class RegionService {
@Autowired
private RegionRepository regionRepository;
public Region getRegion(String regionId) {
Region region = regionRepository.findByRegionId(regionId);
return region;
}
}
As mentioned the whole Region is retrieved.
I tried another way by using a bit more code.
Added an interface:
public interface RegionRepositoryCustom {
Region findByRegionId(String name);
}
And used it to add an impl class:
public class RegionRepositoryImpl implements RegionRepositoryCustom{
@PersistenceContext
private EntityManager em;
@Override
@Transactional
public Region findByRegionId(String id) {
EntityGraph<Region> entityGraph = (EntityGraph<Region>) em.getEntityGraph("Region.id");
Region region = em.createQuery("select r from Region r where r.id = :id", Region.class)
.setParameter("id", id)
.setHint("javax.persistence.fetchgraph", entityGraph)
.getSingleResult();
return region;
}
}
And tried this variant:
public class RegionRepositoryImpl implements RegionRepositoryCustom{
@PersistenceContext
private EntityManager em;
@Override
@Transactional
public Region findByRegionId(String id) {
//EntityGraph<Region> entityGraph = em.createEntityGraph(Region.class);
//entityGraph.addAttributeNodes("id");
EntityGraph<Region> entityGraph = (EntityGraph<Region>) em.getEntityGraph("Region.id");
Map<String, Object> properties = new HashMap<>();
properties.put("javax.persistence.fetchgraph", entityGraph);
Region region = em.find(Region.class, id, properties);
return region;
}
}
Also using H2 with application.properties setting:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
This is the SQL template used seen in the ide's console:
Hibernate:
select
region0_.id as id1_0_,
region0_.name as name2_0_
from
region region0_
where
region0_.id=?
All did not work...
What am I missing?
Upvotes: 4
Views: 3073
Reputation: 603
The EntityGraph is made to eagerly fetch a relation between two entities to fetch it only when it is needed. This has been made because the performance cost of joining tables can be costly and should be done only when specifically needed.
If you really do not want the name, you can remove it from the Entity Region and then it will not be fetched.
More details on entity graphs: https://thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/
Upvotes: 2