ronenwo
ronenwo

Reputation: 107

entitygraph not working - returning all the entity

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

Answers (1)

Ybri
Ybri

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

Related Questions