0

I have a USER object which has many fields having one-to-many mapping with PERMISSION object as well.

I want to fetch only few fields of user with a set of permissions as well. my code is

public class USER {
private Integer id;
private String username;
...
...
...
private Set<Permission> permissions = new HashSet<Permission>();

//setter - getter methods

}

Permission.java

public class Permission {
private String name;
private Integer id;

//setter - getter methods
}

Projection code:

Criteria criteria = session.createCriteria(User.class);
criteria.setCacheable(true);

criteria.add(eq("username", username).ignoreCase());

criteria.createAlias("permissions ", "perm", LEFT_OUTER_JOIN);

ProjectionList projectedFields = Projections.projectionList();
projectedFields.add(Projections.property("id").as("id"));
projectedFields.add(Projections.property("perm.id").as("permissions.id"));

criteria.setProjection(projectedFields);
criteria.setResultTransformer(new AliasToBeanNestedResultTransformer((User.class)));

User user = (User) criteria.uniqueResult();

I'm getting the following exception:

org.hibernate.PropertyNotFoundException: Could not find setter for id on interface java.util.Set
    at org.hibernate.property.ChainedPropertyAccessor.getSetter(ChainedPropertyAccessor.java:66)
    at org.hibernate.transform.AliasToBeanResultTransformer.initialize(AliasToBeanResultTransformer.java:121)
    at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:84)
    at ae.gov.adm.saeed.util.AliasToBeanNestedResultTransformer.transformTuple(AliasToBeanNestedResultTransformer.java:80)
    at org.hibernate.transform.CacheableResultTransformer.retransformResults(CacheableResultTransformer.java:230)

any idea, how to resolve this issue?

oOXAam
  • 237
  • 1
  • 6
  • 20

1 Answers1

0

This doesn't work. This only works for scalar results, but not for nested structures. You would have to build the object graph yourself.

Anyway, this is a perfect use case for Blaze-Persistence Entity Views.

Blaze-Persitence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.

A mapping for your model could look as simple as the following

@EntityView(User.class)
interface ApplicationUser {
    Integer getId();
    @Mapping("permissions.id")
    Set<Integer> getPermission();
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.

ApplicationUser dto = entityViewManager.find(entityManager, ApplicationUser.class, id);

But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

It will only fetch the mappings that you tell it to fetch

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58