1

I'd like to create projection. There is no problem when DTO is flat:

class Projection {
    String id;
    String fieldA;
    String fieldB;
    Projection(String id, String fieldA, String fieldB){
    ...
    }
}

then query will be:

SELECT new Projection(t.id, t.fieldA, t.fieldB) FROM Entity t WHERE t.id...

but I cannot create query for that Projection:

class Projection {
        String id;
        NestedObject nested;
        Projection(String id, NestedObject nested){
        ...
        }
 }
class NestedObject {
    String fieldA;
    String fieldB;
    NestedObject(String fieldA, String fieldB){
    ...
    }
}

I tried like:

SELECT new Projection(t.id, (SELECT new NestedObject(n.fieldA, n.fieldB) FROM Entity n)) FROM Entity t WHERE t.id...

but does not work.

Two questions:

  1. Is it possible?
  2. If answer for 1 is yes, how should this query look like?

2 Answers 2

2

Why don't you create a constructor in Project and use your original query unless some detail is missing from your question?

    class Projection {
      String id;
      NestedObject nested;
    
      Projection(String id, String fieldA, String fieldB){
        this.id = id
        nested = new NestedObject(filedA, fieldB);
      }
    }
Sign up to request clarification or add additional context in comments.

2 Comments

Yes, it is workaround. But I am wondering if solution what I asked is possible.
How to do if we have a native query
0

Its not directly possible because nested constructor invocations are not required by JPQL and no provider supports that AFAIK.

Having said that, this is a perfect use case for Blaze-Persistence Entity Views.

Blaze-Persistence 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.

Assuming you have an entity model like this

@Entity
public class User {
    @Id
    Integer id;
    String role;
    String username;
    @ManyToOne
    Tenant tenant;
}

@Entity
public class Tenant {
    @Id
    Integer id;
    String name;
    String address;
}

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

@EntityView(User.class)
interface UserDto {
    Integer getId();
    String getUsername();
    TenantDto getTenant();
}
@EntityView(Tenant.class)
interface TenantDto {
    Integer getId();
    String getName();
}

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

UserDto dto = entityViewManager.find(entityManager, UserDto.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

3 Comments

Interesting lib. Nice alternative. Thanks for answer. So it is impossible. Then I'll take @Kavithakaran Kanapathippillai flat solution.
How about performances with this library ?
The performance is as good as it gets. It computes lots of stuff on startup to be as efficient as possible at runtime. The main reason for better performance is the fact that the underlying query will only add select items and joins for the parts that are actually needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.