How to fetch all entities which has createdAt parameter type Date by specific Month? - spring

I have a class that has a parameter of type Date.
class MyEntity {
#CreatedDate
#Column(nullable = false, updatable = false)
private Date createdAt;
}
How can I retrieve all those entities where the createdAt is i.e.: in May? Do I need to use #Query or is there a different way to perform it?

Do I need to use #Query?
Yes )
How can I retrieve all those entities where the createdAt is i.e.: in May?
If your JPA provider is Hibernate (I'm sure that it's so), you can use month() and other useful HQL functions in your queries:
#Query("select e from MyEntry e where month(e.createdAt) = ?1")
List<MyEntry> getAllByMonth(int month);

Related

Fetch specific columns dynamically

I have the following User entity:
public class User extends PanacheEntityBase{
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "DataIdGenerator")
#Column(name = "id")
public Long id;
public String name;
public String location;
public int age;
}
I also have the following endpoint: '/user', with a 'select' query parameter where you provide the column names you want to receive. It should be possible to select any combination of columns like: /user?select=id,name, /user?select=id,age, /user?select=name,age, /user?select=age,name
Based on the 'select' query I want to use a projection to get the selected columns only. Currently I'm using the query to create the following query fe: /user?select=id,name to SELECT d.id, d.name FROM User d, however I need the DTO to be dynamic based on the columns provided too.
Currently I have the following projection where UserDTO is a class with id and name attributes. This works fine, but if I change any parameter I need a different DTO.
// This variable is dynamically created based on query parameters
String query = 'SELECT d.id, d.name FROM User d'
return User.find(query).project(UserDTO.class).list();
Is it possible to make this projection DTO class more dynamic, so it supports all combinations?
I suspect the Panache API is not flexible enough at the moment to do what you are asking.
But you could use the Hibernate Reactive API without Panache:
#Inject
Mutiny.SessionFactory sf;
public Uni<List<Tuple>> find(String query) {
return sf.withSession(session ->
session.createQuery(query, Tuple.class).getResultList()
);
}
Once you have the Tuple, you can convert it to the type you prefer.

Spring Data JPA (JPQL) problem: Using TIMESTAMPDIFF function in JPA query

I have the following MySQL query:
select p.name, sum(timestampdiff(MINUTE, r.start_time, r.end_time))
from ride r inner join person p on r.driver_id=p.id
group by p.id
I want to write this in a JPA Query. The code below throws a NullPointerException, it does not work:
#RestResource
public interface SomeRepository extends CrudRepository<Ride, Long> {
#Query("SELECT new com.sample.dto.MyDTO(d.name, SUM(FUNCTION('TIMESTAMPDIFF', 'MINUTE', r.startTime, r.endTime))) " +
"FROM Ride r JOIN r.driver d WHERE r.startTime BETWEEN ?1 AND ?2 " +
"GROUP BY d.id" )
List<MyDTO> findSomething(#Param("startTime") LocalDateTime startTime,
#Param("endTime") LocalDateTime endTime);
}
If I use DATEDIFF function, it works.
FUNCTION('DATEDIFF', r.startTime, r.endTime)
But I need the exact difference in minutes. TIMESTAMPDIFF satisfies my needs.
After failure of finding how to do this with JPA, I returned to native query but this is not good. Any alternatives?
I use the latest spring-data-jpa (2.1.3), hibernate-core:5.3.7
public class Ride {
#Column(name = "start_time")
private LocalDateTime startTime;
#Column(name = "end_time")
private LocalDateTime endTime;
}
The goal is to find total difference between startTime and endTime (in minutes). Is there a way to do this with standard (portable) JPA?
Actually, there is no TIMESTAMPDIFF in JPQL.
Reference: timestampdiff equivalent in JPQL (without using criteria)
So, What you can do is that you can use TIME_TO_SEC(TIMEDIFF(r.startTime, r.endTime)) / 60 instead of using FUNCTION('TIMESTAMPDIFF', 'MINUTE', r.startTime, r.endTime)
There is no registerFunction('TIMESTAMPDIFF') in org.hibernate.dialect.MySQLDialect.
But registerFunction('DATEDIFF') exists.
So you cant use TIMESTAMPDIFF in jpa.
You can add custom function or use custom Dialect.
But I suggest using unix_timestamp() instead.
(function('unix_timestamp', startTime)-function('unix_timestamp', endTime))/60

Spring Data JPA query to select all value from one join table

I have problem to select all value from one table and few other columns using Spring Data JPA. I am using PostgreSql database and when I send query through PgAdmin I get values I want, but if I use it in Spring Boot Rest returns only one table values (subquery not working). What I am doing wrong?
#Query(value = "SELECT item.*, MIN(myBid.bid) AS myBid, (SELECT MIN(lowestBid.bid) AS lowestbid FROM bids lowestBid WHERE lowestBid.item_id = item.item_id GROUP BY lowestBid.item_id) FROM item JOIN bids myBid ON item.item_id = myBid.item_id WHERE myBid.user_id = :user_id GROUP BY item.item_id", nativeQuery = true)
public List<Item> findAllWithDescriptionQuery(#Param("user_id") UUID userId);
Added Item class
#Data
#Entity(name = "item")
public class Item {
#Id
#GeneratedValue
private UUID itemId;
#NotNull
#Column(name = "title")
#Size(max = 255)
private String title;
#NotNull
#Column(name = "description")
private String description;
#NotNull
#Column(name = "created_user_id")
private UUID createdUserId;
}
The result from your native query cannot simply be mapped to entities due to the in-database aggregation performed to calculate the MIN of own bids, and the MIN of other bids. In particular, your Item entity doesn't carry any attributes to hold myBid or lowestbid.
What you want to return from the query method is therefore a Projection. A projection is a mere interface with getter methods matching exactly the fields returned by your query:
public interface BidSummary {
UUID getItem_id();
String getTitle();
String getDescription();
double getMyBid();
double getLowestbid();
}
Notice how the query method returns the BidSummary projection:
#Query(value = "SELECT item.*, MIN(myBid.bid) AS myBid, (SELECT MIN(lowestBid.bid) AS lowestbid FROM bids lowestBid WHERE lowestBid.item_id = item.item_id GROUP BY lowestBid.item_id) FROM item JOIN bids myBid ON item.item_id = myBid.item_id WHERE myBid.user_id = :user_id GROUP BY item.item_id", nativeQuery = true)
public List<BidSummary> findOwnBids(#Param("user_id") UUID userId);
Return type is List of Item objects and the query specified is having columns which are not part of return object. I recommend using appropriate Entity which full-fills your response type.

Fetch child entities when finding by a normal field in Spring Data JPA

I am using Spring Data JpaRepository to find List of entities matching a particular field. Consider the following code snippet:
Entity:
#Entity
#Table(name = "master")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Master implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "id", nullable = false)
private Long Id;
#NotNull
#Column(name = "user_id", nullable = false)
private String userId;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="id", referencedColumnName="id", insertable=false, updatable=false)
private Details Details;
Spring Data Custom JpaRepository:
public interface MasterRepository extends JpaRepository<Master,Long> {
List<Master> findMasterByUserId(String userId);
}
When i am using findBookingMasterByUserId repository method to find all records with specific user id, I am getting the List of Master entity but I am not getting the Details entity that has id as foreign key in it.
However, I get all the dependent entities when I use out of the box findAll method of JpaRepository but with custom findMasterByUserId repository method, child entities are not being fetched eagerly.
Any type of help would be highly appreciated. Thanks!
You can use #EntityGraph in your repo to eagerly get associated data:
#EntityGraph(attributePaths = {"details"})
List<Master> findBookingMasterByUserId(String userId);
P.S. Don't forget to change 'Details' field to details;
Your entity name is "Master" not "booking_master".
Change your method to:
List<Master> findByUserId(String userId);
Refer to below spring docs for more information on query creation mechanism for JPA.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
Alternatively,
#Query("SELECT m FROM Master m WHERE m.userId = :userId")
List<Master> findByUserId(#Param("userId") String userId);
The query generation from the method name is a query generation strategy where the invoked query is derived from the name of the query method.
We can create query methods that use this strategy by following these rules:
The name of our query method must start with one of the following
prefixes: find…By, read…By, query…By, count…By, and get…By.
If we want to limit the number of returned query results, we can add
the First or the Top keyword before the first By word. If we want to
get more than one result, we have to append the optional numeric
value to the First and the Top keywords. For example, findTopBy,
findTop1By, findFirstBy, and findFirst1By all return the first entity
that matches with the specified search criteria.
If we want to select unique results, we have to add the Distinct
keyword before the first By word. For example, findTitleDistinctBy or
findDistinctTitleBy means that we want to select all unique titles
that are found from the database.
We must add the search criteria of our query method after the first
By word. We can specify the search criteria by combining property
expressions with the supported keywords.
If our query method specifies x search conditions, we must add x
method parameters to it. In other words, the number of method
parameters must be equal than the number of search conditions. Also,
the method parameters must be given in the same order than the search
conditions.

JPA Criteria API query with Join and inheritance

I am trying to write Query using JPA Criteria API. I have the following classes:
Class Booking {
#ForeignKey(name = "BVisit_ID_FK")
private List<BVisit> BVisits = new LinkedList<>();
//other properties
...
}
Class Visit{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private Long id;
}
Class VisitSpecial extends Visit{
#Column(name = "ARRIVAL_TIME", nullable = false)
private Date arrivalTime;
#Column(name = "DEPARTURE_TIME", nullable = false)
private Date departureTime;
//other properties...
}`
How can I write query using JPA Criteria Api (and metamodels) that will find all bookings that have
visits with date value(parameter) that is between min arrival time, an max departure time for its booking visits.
I use org.springframework.data.jpa.domain.Specification
The query should look like something like this:
SELECT Booking
from Booking B, Visit V, VisitSpecial VS
where Visit.bookingId = Booking.id and Visit.id = VisitSpecial.id
and VisitSpecial.arrivalTime = (SELECT MIN(VisitSpecial.arrivalTime) from VisitSpecial VS1 WHERE V.id = VS1.id)
and VisitSpecial.arrivalTime <= :date
and VisitSpecial.departureTime = (SELECT MAX(VisitSpecial.departureTime) from VisitSpecial VS1 Where V.id = VS1.id)
and VisitSpecial.departureTime >= :date
See my answer here for dealing with InheritanceType.JOINED and other inheritance strategies through JPA Criteria Subquery.
Downcasting with treat may work, but I do not recommend it for complex queries as it may produce inefficient queries (redundant joins) or not work at all based on your JPA provider (Hibernate, Eclipselink, etc.).

Resources