get latest record from table using postgresql - java

I have table employee as below,
id|name1|number
--|-----|------
01|test |100
02|test1|101
03|test2|102
I am using jpa with eclipselink implementation and database is postgresql.
Here my requirement is I want to get latest record using select query. Can anyone suggest the query to get latest record always.
Thanks,

You can use the below query for getting the appropriate result from mysql
select * from employee order by id desc limit 1

You must add updatedDate field in the entity class.
So I'll like to know if is there a SIMPLE way around my problem, meaning having #PrePersist or #PreUpdate or even other workaround to set the lastModified field still using session
Entity Class:
#Entity
#Table(name = "employee")
public class Employee {
#Id
#GeneratedValue
private Long id;
#Column(name = "name")
private String name;
#Column(name = "number")
private Long number;
#Column(name = "updated_at")
#Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
// getter setter
#PreUpdate
public void setChangeDate() {
this.updatedAt = new Date();
}
}
You can use JPA query. This exam:
String query = "SELECT emp FROM Employee emp order by updatedAt desc limit 1 ";

Related

Query auto generated table in Spring Boot

I have 2 entities.
One being Courses and other one Batch
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
public class Course {
#Id
private String uuid;
#Column
private String tileImage;
#Column
private String description;
#Column
private Boolean isActive;
#Column
private String name;
#Column
private String durationWeek;
#Column
private String durationHour;
#Column
private int price;
#Column
private String apply;
#Column
private Integer linkClicked;
#Column
#OneToMany(cascade = CascadeType.ALL)
private Set<Batch> batches;
}
And one is Batch
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
public class Batch {
#Id
private String uuid;
#Column
private Date startDate;
#Column
private Date endDate;
#Column
private String taughtBy;
}
On running in Spring boot, it generates 3 table
Course
Batch
Courses_batches (coueseUUid and BatchUUid)
Issue is I want to query the Courses_Batches table? How can I do that by Spring JPA?
It really depends on the result you want: you probably don't want the tuple Course_Batches which represents the association between Course and Batch, you probably want all Course that matches Batches or the reverse.
This association does not have any specify attribute, and if were to have attributes, there should be an intermediate entity.
You could use a Spring Data #Query, the findBy variant or a Criteria: here I assumed that you can use Java multiline string for clarity, but you would have to use concatenation and space for older version of Java:
#Query("""
select new com.example.foobar.PairCourseBatch(c, b)
from Course c
left join c.batches b
where c.uuid = :courseUuid
and b.uuid = :batchUuid
""")
List<PairCourseBatch> findAllByCourseIdInJoinTable(
#Param("courseUuid") String courseUuid,
#Param("batchUuid") String batchUuid
);
The PairCourseBatch should be a fully qualified type in the query because otherwise JPA would not be able to find it. It expect a constructor taking the course and batch as parameter.
I don't know if you can use generics (eg: Pair<Course, Batch>) but you could return specific attribute and construct a non entity type:
select new com.example.foobar.PairCourseBatch(c.tileImage, b.startDate, b.endDate)
The advantage of using it is cleared in the return type: you don't have to cast component of an Object[].
Spring Data provides many ways to define a query that we can execute. One of these is the #Query annotation.
You can use also native SQL to define our query. All we have to do is set the value of the nativeQuery attribute to true and define the native SQL query in the value attribute of the annotation:
#Query(value = "SELECT * FROM Courses_Batches cb WHERE cb.course_uuid = ?1",
nativeQuery = true)
Object[] findAllByCourseIdInJoinTable(String courseId);
You set the column names according to your structure.

How to check that all hibernate queries for a table have a condition for a specific column?

We have a deleted column on our table, is it possible to check that every time this table is queried the query has a condition for this column?
Some googling with better keywords (soft-delete) it seems I could do this with #When annotation. not exactly what I was looking but seems close enough.
You can check out #Where annotation.
org.hibernate.annotations.Where
Example:
If there's an Account Entity
#Entity(name = "Account")
#Where( clause = "active = true" )
public static class Account {
#Id
private Long id;
#ManyToOne
private Client client;
#Column(name = "account_type")
#Enumerated(EnumType.STRING)
private AccountType type;
private Double amount;
private Double rate;
private boolean active;
//Getters and setters omitted for brevity
}
and if the following code is used for fetching the accounts.
List<Account> accounts = entityManager.createQuery(
"select a from Account a", Account.class)
.getResultList();
then the following SQL will be generated
SELECT
a.id as id1_0_,
a.active as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE ( a.active = true )
Hibernate ORM 5.2.18.Final User Guide

Get collections within an Entity when mapping it to DTO using Transformers

I have an Entity called Student
#Entity
#Table(name = "students")
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "STUDENT_ID")
private Integer studentId;
#Column(name = "STUDENT_NAME", nullable = false, length = 100)
private String studentName;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "student", cascade = CascadeType.ALL)
private List<Note> studentNotes;
// Some other instance variables that are not relevant to this question
/* Getters and Setters */
}
and an entity called as Note
#Entity
#Table(name = "notes")
public class Note implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "NOTE_ID")
private Integer noteId;
#Column(name = "NOTE_CONTENT")
private String noteText;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "STUDENT_ID")
private Student student;
/* Getters and Setters */
}
As you can see the relationship dictates that a Student can have multiple number of notes.
For displaying some information about the student on a particular page I need only the studentName, count of notes and all the notes.
I created a StudentDTO for that and it looks something like this:
public class StudentDTO {
private Long count;
private String name;
private List<Note> notes;
/* Getters and setters */
}
And I am using the following code to map the Student and Notes returned from the DB to the StudentDTO
private static void testDTO() {
Session session = getSessionFactory().openSession();
String queryString = "SELECT count(n) as count, s.studentName as name, s.studentNotes as notes " +
"from Student s join s.studentNotes n where s.id = 3";
Query query = session.createQuery(queryString);
List<StudentDTO> list = query.setResultTransformer(Transformers.aliasToBean(StudentDTO.class)).list();
for (StudentDTO u : list) {
System.out.println(u.getName());
System.out.println(u.getCount());
System.out.println(u.getNotes().size());
}
}
The above code fails when there are notes fetched in the query but if I remove the notes and get only name and count it works fine.
When notes is included in the query, this is the error that is fired by Hibernate:
select
count(studentnot2_.NOTE_ID) as col_0_0_,
. as col_3_0_,
studentnot3_.NOTE_ID as NOTE_ID1_2_,
studentnot3_.NOTE_CONTENT as NOTE_CON2_2_,
studentnot3_.STUDENT_ID as STUDENT_3_2_
from
students studentx0_
inner join
notes studentnot2_
on studentx0_.STUDENT_ID=studentnot2_.STUDENT_ID
inner join
notes studentnot3_
on studentx0_.STUDENT_ID=studentnot3_.STUDENT_ID
where
studentx0_.STUDENT_ID=3;
And this is the error message that I get:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as col_3_0_, studentnot3_.NOTE_ID as NOTE_ID1_2_, studentnot3_.NOTE_CONTENT as N' at line 1
Now I can see where the query is wrong but it is generated by Hibernate, not something that I have control on. Is there something that I need to change in my queryString to acheive the result that I need.
I do not want to manually map the results to my DTO, is there a way that I can directly map my studentNotes in Student.java to notes in StudentDTO.java
Looks like this query is wrong. The better way is to get just the student. You can always get collection of notes from a student.
Session session = getSessionFactory().openSession();
String queryString = from Student s where s.studentId = 3;
Query query = session.createQuery(queryString);
Student student = query.getSingleResult();
sysout(student.getNotes().size())
Also, I never retrieved collection this way in SELECT clause; so, not sure but do you really need
join s.studentNotes
in your query? Not sure if my answer is helpful.
Your query is wrong as you would need two joins to also select the count of notes, but that's not even necessary, as you could determine the count by just using the size of the notes collection.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(Student.class)
interface StudentDTO {
#Mapping("studentName")
String getName();
#Mapping("studentNotes")
List<NoteDTO> getNotes();
default int getCount() { return getNotes().size(); }
}
#EntityView(Note.class)
interface NoteDTO {
// attributes of Note that you need
#IdMapping Integer getId();
String getNoteText();
}
Querying could look like this
StudentDTO student = entityViewManager.find(entityManager, StudentDTO.class, studentId);

JPA Join table with SELECT

I have a SQL query like this:
SELECT h.name, h.created_date, tbl.*
FROM my_table tbl
LEFT JOIN
(SELECT name, max(created_date) created_date FROM my_table GROUP BY name) h
ON tbl.name = h.name;
It returns the row from my_table (which has multiple for name="") along with the maximum created_date for that name.
Is there a way to replicate this in a JPQL query?
Here is the gist of the Entity class, it's quite simple:
#Entity
#Table(name = "MY_TABLE")
#XmlRootElement
public class MyTable implements Serializable {
private BigDecimal tableId;
private String name;
private Date createdDate;
// ...
#Id
#Basic(optional = false)
#Column(name = "TABLE_ID")
#GeneratedValue(generator = "TBL_ID_SEQ")
public BigDecimal getTableId() {
return tableId;
}
#Basic(optional = false)
#Column(name = "NAME")
public String getName() {
return name;
}
#Basic(optional = false)
#Column(name = "CREATED_DATE", insertable = false)
#Temporal(TemporalType.TIMESTAMP)
public Date getCreatedDate() {
return createdDate;
}
// ... getters/setters
}
Just reading your question I guess you do not need another entity. Entities in JPA are the same like tables in SQL. Usually there is a 1:1 relationship between entities and tables. You just have to know how to invoke a query using JPQ. You need a entity manager, which invokes your statement.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnit");
EntityManager em = emf.createEntityManager();
You have to define your persistence unit, i.e. in a pom file, or a config java file. So done you can go on coding something like this:
Query q = em.createQuery( "Your query in sql syntax as a string object" );
In respect to your entities and invoked query you will receive a List using
List<object> resultOfMyQuery = q.getResultList();
This is only one short example. But hopefully you got some buzzwords to look for ;)

Hibernate - createQuery not fetching timestamp

Envrionment: Java, Hibernate JPA provider, JPA, Oracle DB
I am trying to create a native query to fetch the data from the Oracle DB. One of the columns is a date column. The date is fetched, but the timestamp is coming out as 00:00:00. However, through an SQL browser, I can see the date and the time. How do I fetch the resultList along with the time?
org.hibernate.Query query = ((HibernateEntityManager) entityManager).getSession().
createSQLQuery(NATIVE_QUERY).setResultTransformer(org.hibernate.transform.Transformers.ALIAS_TO_ENTITY_MAP);
query.setString(0, accountNumber);;
query.setTimestamp(1, startDate).setTimestamp(2, endTime);
query.setTimestamp(3, startDate).setTimestamp(4,endTime);
List resultList = query.list();
The query itself (in the code above - NATIVE_QUERY) is a normal SQL query for - "Get me all user names and txn time within a given date range whether it is a new transaction or something that has changed in some form".
select u.first_name as firstName, u.last_name as lastName, tx.start_time as txnTime from user u, transaction tx where tx.user_id=u.user_id and tx.account_number=? and (tx.start_time > ? and tx.start_time < ? or tx.change_time > ? and tx.change_time < ?)
for(Object listItem : resultList){
Map map = (Map) listItem;
Date txnTime = (Date)map.get("txnTime".toUpperCase());
//--------> NOT FETCHING THE TIME. I get the time as 00:00:00
}
The domain model is very simple
#Entity
#Table(name="TRANSACTION")
#org.hibernate.annotations.Entity(
dynamicUpdate = true
)
public class Transaction{
#Id
#SequenceGenerator(name="txn_gen", sequenceName="TXN_S")
#GeneratedValue(generator="txn_gen")
#Column(name="TXN_ID")
private Long txnId;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID", nullable=false)
private User user;
#Column(name="START_TIME", nullable=false)
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date startTime;
#Column(name="CHANGE_TIME")
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date changeTime;
}
#Entity
#Table(name="USER")
#org.hibernate.annotations.Entity(
dynamicUpdate = true
)
public class User {
#Id
#SequenceGenerator(name = "user_gen", sequenceName = "USER_S")
#GeneratedValue(generator = "user_gen")
#Column(name="USER_ID")
private Long userId;
#Column(length=500, name="FIRST_NAME")
private String firstName;
#Column(length=500, name="LAST_NAME")
private String lastName;
}

Categories

Resources