How to get a List in one of the fields of DTO JPA Repository - spring-boot

I have a DTO and one of its field is a list. So, there is a main table and another table with one to many relations.
Code:
public class DTO {
id;
List<String> name;
}
public interface Repository extends JpaRepository<Table1, Long> {
#Query("SELECT new abc.com.DTO (" +
" r.id," +
" name"+
" )" +
" FROM Table1 r" +
" join Table2 c on c.xyz.id = r.abc.id"+
" WHERE r.type = :type"
)
List<DTO> find(#Param("type") final String type);
}
say I have in table T1 a row against which we have 3 rows in table 2.
I want dto to get me object obj1 with a list of all 3 names for table2
Currently it returns me 3 separate dtos with 3 rows of table2

As it is stated in the JPA specification (see section 4.8 SELECT Clause):
The SELECT clause can contain one or more of the following elements: an identification variable that ranges over an abstract schema type, a single-valued path expression, a scalar expression, an aggregate expression, a constructor expression.
Note that the SELECT clause must be specified to return only single-valued expressions. So, the query like below is therefore not valid:
SELECT o.lineItems FROM Order AS o

This is not possible with JPA directly as constructor expressions always use flat results. Spring Data Projections should support this, but in an inefficient way i.e. it selects entities and just provides a "view" of these entities through an interface.
I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Table1.class)
public interface DTO {
#IdMapping
Long getId();
#Mapping("Table2[xyz.id = VIEW(abc.id)].name")
Set<String> getNames();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
DTO a = entityViewManager.find(entityManager, DTO.class, id);
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
public interface Repository extends JpaRepository<Table1, Long> {
List<DTO> findByType(#Param("type") final String type);
}

Related

How do I define a custom JOIN condition in a query method of a JpaRepository

We have an ArticleEntity that has several Prices, and the Prices are only valid in a certain time range, and there is only one valid price at a time.
In our entities this is modeled:
#Entity
public class ArticleEntity {
...
#OneToMany(mappedBy = "article", fetch = FetchType.LAZY)
private Collection<PriceEntity> prices;
}
Now, in our ArticleRepository I am trying to add custom query so that only valid prices are retrieved:
public interface ArtikelRepository extends JpaRepository<ArtikelEntity, Integer> {
#Query(value = "select a, p from ArtikelEntity a left join fetch PriceEntity p on p.article = a " +
"and (p.start is null or p.start <= :date) " +
"and (p.end is null or p.end >= :date) ")
Collection<ArtikelEntity> findAllWithPriceOnDate(#Param("date") LocalDate date);
}
Unfortunately this does not work, as Hibernate/JPA is requesting all prices afterwards again, instead of populating the price list with just the result of this join query.
Can I tell Hibernate/JPA to use the data from the custom query? And how?
It's not really possible unless you use Hibernate filters. I would recommend you to look into a DTO solution though, because even with filters, you could run into a situation where you change the collection and all of a sudden Hibernate flushes the state i.e. removes elements which are filtered out.
I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(ArtikelEntity.class)
public interface ArtikelDto {
#IdMapping
Long getId();
String getName();
#Mapping("prices[(start is null or start <= :date) " +
"and (end is null or end >= :date)]")
Set<PriceDto> getValidPrices();
#EntityView(PriceEntity.class)
interface PriceDto {
#IdMapping
Long getId();
BigDecimal getPrice();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ArtikelDto a = entityViewManager.find(entityManager, ArtikelDto.class, id);
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
Page<ArtikelDto> findAll(#OptionalParam("date") LocalDate date, Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!

Spring JPA Two Entities for same DB table

I am writing Spring Boot Data JPA application and I have following situation:
I have 2 database queries fetching from same table but they are fetching different columns and data based on their WHERE clauses. For example:
SELECT CAR_TYPE, CAR_MODEL, CAR_YEAR, ACCIDENT_YEAR, BUY_DAY FROM CAR WHERE ACCIDENT_YEAR IS NULL
, and
SELECT CAR_MODEL, CAR_YEAR FROM CAR WHERE CAR_YEAR >= CURRENT_YEAR
As you can see these 2 queries (whose results will be exposed through 2 different API points) reference the same table CAR, but return different fields and have different WHERE clauses.
I know in JPA, I have to create an entity CarEntity like:
#Entity
#Table(name = "CAR")
public class CarEntity {
// I can only have fields from one or the other query
// here, so I guess I have to have 2 of these
}
, but my problem is that this entity needs to apply for the 2 different queries (with different fields returned, different data, different WHERE clauses).
So, it looks like I have to have actually 2 CarEntity classes. But, I am not sure how to make these 2 CarEntities so they both reference the same table CAR?
You can do by using projection that basically you define an interface with field methods which you want to get them. Projections
#Entity
public class Car implement CarSummary { // if you want you can implement JIC
private UUID id;
private String carType;
private String carModel;
private LocalDateTime carYear;
//getters and setters
}
public interface CarSummary {
String getCardModel();
String getCarYear();
}
Then on your query.
public interface CarRepository extends Repository<Car, UUID> {
Collection<CarSummary> findByCarYearGreaterThan(LocalDateTime now);
Collection<Car> findByAccidentYearIsNull();
}

Can I select specific fields from entity with EntityGraph?

I have an entity, which has multiple(lets say more than 5) fields in it. I want to list only 2 of the fields in entity. I managed to do it with Entity Manager and JPA Query. In the code below, I added how I did it with entity manager, but it may not be optimal solution. What I want to ask is, can I do that with using the EntityGraph?
List<Object[]> test = entityManager.createQuery("SELECT c.a, c.b FROM TestClass c WHERE c.id = :id", Object[].class)
.setParameter("id", id)
.getResultList();
TestClassResult testClassResult = new TestClassResult();
for (Object[] row : test) {
testClassResult.setA((BigDecimal) row[0]);
testClassResult.setB((BigDecimal) row[1]);
}
As far as I know, an implementation is allowed to fetch only what you specify when registering an entity graph as fetch graph (different from a load graph), but at least Hibernate does not support this.
Anyway, DTO projections are usually the way to in such a case anyway and I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(TestClass.class)
public interface TestClassResult {
#IdMapping
Integer getId();
BigDecimal getA();
BigDecimal getB();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
TestClassResult a = entityViewManager.find(entityManager, TestClassResult.class, id);
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
Page<TestClassResult> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
as far as I know, entity graphs define which attributes to fetch from the database so you can fetch the 2 attributes eagerly and the other 3 lazily, "Thorben Janssen" has a good article on his website about graphs, another way to exclusively fetch selected attributes is to use DTO Projections, he also does have a good article touching the subject.

Spring data JPA for returning specific fields

Does Spring Data have a mechanism for returning specific fields?
I'm familiar with the syntax:
Invoice findByCode(String code);
How about this:
Integer findIdByCode(String code);
which returns the id field only. Or
Tuple findIdAndNameByCode(String code);
which returns a tuple. Or
Invoice findIdAndNameByCode(String code);
which returns an entity only populated with specific fields. Can use a constructor taking only those field if defined - else construct empty and populate the fields.
EDIT
To qualify some more, I'm aware of solutions like #Query, constructor expressions and now, #NamedEntityGraph. My question is simply - does Spring data support such a shorthand syntax as I'm suggesting?
If not, perhaps this is a cool enhancement for a later version...
I'm not looking for workarounds.
You can use JPQL Constructor Expressions:
SELECT NEW com.company.PublisherInfo(pub.id, pub.revenue, mag.price)
FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
The constructor name must be fully qualified
If you want to return just 1 field from table and it's primitive(or autoboxing), you can use next:
#Query("select distinct t.locationId from Table t")
List<Long> findAllWashroomLocationId();
Where:
Table - name of class which represent your table
t - alias
locationId - name of field(in your Table object)
Long - type of locationId (Integer, String, ...)
Not sure if what you're trying to achieve is the same as using multiple projections on the same JPA generated query (where method name are the same). I have posted an answer in this post.
https://stackoverflow.com/a/43373337/4540216
So I've managed to figure out how to use multiple projections with a
single query.
<T> T getByUsername(String username, Class<T> projection) This allows the method caller to specified the type of projection to be
applied to the query.
To further improve this so it is less prone to error, I made a blank
interface that the projection will have to extend in order to be able
to insert class into the parameter.
public interface JPAProjection {
}
public interface UserRepository extends CrudRepository<UserAccount, Long> {
<T extends JPAProjection > T getByUsername(String username, Class<? extends JPAProjection> projection);
}
Projection Interface
public interface UserDetailsProjection extends JPAProjection{
#Value("#{target.username}")
String getUsername();
#Value("#{target.firstname}")
String getFirstname();
#Value("#{target.lastname}")
String getLastname();
}
Then I can call the query method by
getByUsername("...", UserDetailsProjection.class)
i have a nativequery,
this is a insert and i going to return all fields after insert whit "RETURNING *"
this query return all fields of my database, and this data going to save in my entity
"Perfil Detalles"
my entity have all configurations of my fields of my database
#Query(
value= "INSERT INTO \"USUARIO\".\"PERFIL_CONFIGURACION\" (id_perfil, id_group, id_role) VALUES(:id_perfil, :id_group, :id_role) returning *",
nativeQuery = true)
public PerfilDetalles insertPerfilDetalles(
#Param("id_perfil") Long id_perfil,
#Param("id_group") int id_group,
#Param("id_role") int id_role);

Select fews columns (DTO) with specification JPA

I am using spring-data-jpa version 1.5.1.RELEASE .
My domain is :
public class MyDomain{
....
....
private String prop1;
private String prop2;
......
......
}
My JPA Specification is:
public final class MyDomainSpecs {
public static Specification<MyDomain> search(final String prop1,final String prop2) {
return new Specification<MyDomain>() {
public Predicate toPredicate(Root<MyDomain> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
// Some tests if prop1 exist .....
Predicate predicate1 = cb.equal(root.get("prop1"), prop1);
Predicate predicate2 = cb.equal(root.get("prop2"), prop2);
return cb.and(predicate1, predicate2);
}
};
}
}
My Repository :
public interface MyDomainRepository extends JpaRepository<MyDomain, Long>, JpaSpecificationExecutor<MyDomain> {
List<MyDomain> findAll(Specification<MyDomain> spec);
}
All is Working .
But my need (For performance DB tunning) is to not return and select all fields of MyDomain from DB .
I need to select only for example tree properties (prop1, prop2, prop3) , idealy in a DTO Object .
I don't want to convert My List<MyDomain> to List<MyDto> because i am tunning DB request .
So , I don't find any way to do that with spring-data-Jpa and Specification .
Any Idea ?
Thanks
This is not possible as for now. There is a ticket for this but no idea if it will be ever implmented: https://jira.spring.io/browse/DATAJPA-51
Create a special version of MyDomain (e.g. MyDomainSummary or LightMyDomain) that only includes the fields you want to map.
Basic example
Borrowed from the excellent JPA WikiBook.
Assume a JPA entity (i.e. domain class) like so:
#Entity
#Table(name="EMPLOYEE")
public class BasicEmployee {
#Column(name="ID")
private long id;
#Column(name="F_NAME")
private String firstName;
#Column(name="L_NAME")
private String lastName;
// Any un-mapped field will be automatically mapped as basic and column name defaulted.
private BigDecimal salary;
}
The SQL query generated will be similar to
SELECT ID, F_NAME, L_NAME, SALARY FROM EMPLOYEE
if no conditions (where clause) are defined. So, to generalize the basic case one can say that the number of queried columns is equal to the number of mapped fields in your entity. Therefore, the fewer fields your entity, the fewer columns included in the SQL query.
You can have an Employee entity with e.g. 20 fields and a BasicEmployee as above with only 4 fields. Then you create different repositories or different repository methods for both.
Performance considerations
However, I seriously doubt you'll see noticeable performance improvements unless the fields you want to omit represent relationships to other entities. Before you start tweaking here log the SQL that is currently issued against the data base, then remove the columns you want to omit from that SQL, run it again and analyze what you gained.

Resources