I'm trying to do a multiple update using JPA. What I currently now, It's that is possibly to update multiple columns records in a same entity using JPA. I'm trying to avoid using update statements in loop but I couldn't find any information about this.
I'm using an entity manager in order to execute the queries
#Override
public void updateAllNotes(List<Note> NOTES) {
LocalTime now = LocalTime.now(ZoneId.of("America/Mexico_City"));
String query = "UPDATE Note SET TITLE = :title, CONTENT = :content, UPDATED_AT = :updatedAt WHERE ID = :id";
/* I'm trying to avoid this */
for (Note note:NOTES) {
entityManager.createQuery(query)
.setParameter("title", note.getTitle())
.setParameter("content", note.getContent())
.setParameter("updatedAt", now)
.setParameter("id", note.getId())
.executeUpdate();
}
}
You can try below code may be it helpful or you can refer JPA - Batch/Bulk Update - What is the better approach?.
public void updateAllNotes(List<Note> NOTES) {
LocalTime now = LocalTime.now(ZoneId.of("America/Mexico_City"));
List<Integer> idList = NOTES.stream().map(Note::getId).collect(Collectors.toList());
String query = "UPDATE Note SET TITLE = (?1), CONTENT = (?2), UPDATED_AT = (?3) WHERE ID = (?4)";
entityManager.createQuery(query)
.setParameter(1, note.getTitle())
.setParameter(2, note.getContent())
.setParameter(3, now)
.setParameter(4, idList)
.executeUpdate();
}
Related
Am upgrading Hibernate from 5.1.2.Final to 5.4.13. Am facing issue in below code,
#Entity
#NamedNativeQuery(name = "getStudentDetails", resultClass = StudentEntity.class, query = "{call getStudentDetails(?)}")
public class StudentEntity {
private Long id;
private String name;
}
and my DAO class like below,
public List<StudentEntity> getStudentDetails(){
List<StudentEntity> result = null;
try{
Query query = em.createNamedQuery("getStudentDetails");
result = query.getResultList();
}catch(Exception e){
}
return result;
}
create or replace procedure getStudentDetails(p_return_cur OUT SYS_REFCURSOR) is Store procedure with only output parameter.
am not set outparameter in java code. Till Hibernate 5.2.* don't have this issue. When update to 5.3.* it return "ordinal parameter not bound 1".
Positional Parameters are not Supported since 5.3
Support for legacy-style query parameter ('?') declarations in HQL/JPQL queries has been removed. This feature has been deprecated since Hibernate 4.1 and finally removed in 5.3 version.
Therefore, the following query declaration is not valid:
Query<Product> query = OBDal.getInstance().getSession()
.createQuery("from Product as p where p.name = ? and p.stocked = ?", Product.class);
query.setParameter(0, "Ale Beer");
query.setParameter(1, true);
To make the previous query work fine it must use named parameters:
Query<Product> query = OBDal.getInstance().getSession()
.createQuery("from Product as p where p.name = :name and p.stocked = :isStocked", Product.class);
query.setParameter("name", "Ale Beer");
query.setParameter("isStocked", true);
Code sample is taken from http://wiki.openbravo.com/wiki/Hibernate_5.3_Migration_Guide
I've a database with many thousands of tables that have been (and continue to be) created with a naming strategy - one table per calendar day:
data_2010_01_01
data_2010_01_02
...
data_2020_01_01
All tables contain sensor data from the same system in the same shape. So a single entity (lets call it SensorRecord) will absolutely map to all tables.
I'd imagined something like this would work:
#Query(nativeQuery = true, value = "SELECT * FROM \"?1\"")
Collection<SensorRecord> findSensorDataForDate(String tableName);
But it does not, and reading around the topic seems to suggest I am on the wrong path. Most posts on dynamic naming seem to state explicitly that you need one entity per table, but generating thousands of duplicate entities also seems wrong.
How can I use JPA (JPQL?) to work with this data where the table name follows a naming convention and can be changed as part of the query?
Parameters are only allowed in the where clause.
You can create custom repository method returns collection of SensorRecord dto. No need to map so many entities. You should get List<Object []> as query result and manually create dto objects.
#Autowired
EntityManager entityManager;
public List<SensorRecord> findSensorDataForDate(LocalDate date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd");
String tableName = "data_" + date.format(formatter);
Query query = entityManager.createNativeQuery(
"select t.first_column, t.second_column from " + tableName + " t");
List<Object[]> queryResults = query.getResultList();
List<SensorRecord> sensorRecords = new ArrayList<>();
for (Object[] row : queryResults) {
SensorRecord record = new SensorRecord();
record.setFirstParameter((Integer) row[0]);
record.setSecondParameter((String) row[1]);
sensorRecords.add(record);
}
return sensorRecords;
}
Could it be just syntax error?
This has worked for me:
#Query(value = "select * from job where job.locked = 1 and job.user = ?1", nativeQuery = true)
public List<JobDAO> getJobsForUser(#Param("user") String user);
I am trying to do "sql interpreter" in my web-app, only for CRUD. Everything work fine, I am using method prepareStatement() to execute query. But I have problem with operation select :
When I use the select operation only for 1 field, then parsing to a string gives a fairly good result:
for(String x: resultList){
System.out.println(x);
}
Is there any way to execute:
SELECT field_1, field_2, field_3 FROM table;
and print result in console, with some neat form without use Entites?
Well if it isn't possible, is there any way to generate entity "on the fly"? I mean generate Entities using java code.
You could use a native query and explicitly specify which columns you want to select:
String sql = "SELECT field_1, field_2, field_3 FROM table";
Query q = em.createNativeQuery(sql);
List<Object[]> results = q.getResultList();
for (Object[] r : results) {
System.out.println("(field_1, field_2, field_3) = (" + r[0] + ", " + r[1] + ", " + r[2] + ")");
}
With Spring Data JPA Projections
If you already use some entities and Spring Repository then you can add this code to one of them. Thanks Spring Data JPA Projections.
public interface SomeEntityRepository extends Repository<SomeEntity, Long> {
#Query(value = "SELECT field_1, field_2, field_3 FROM table", nativeQuery = true)
List<TableDto> getFromTable();
}
Where TableDto:
public interface TableDto{
Long getField_1();
String getField_2();
String getField_3();
}
With Spring JdbcTemplate
Or use Spring JdbcTemplate:
String query = "SELECT field_1, field_2, field_3 FROM table where id = ?";
List<TableDto> resluts = jdbcTemplate.queryForObject(
query, new Object[] { id }, new TableDtoRowMapper());
public class TableDtoRowMapper implements RowMapper<TableDto> {
#Override
public TableDtomapRow(ResultSet rs, int rowNum) throws SQLException {
TableDto dto = new TableDto();
dto.setField_1(rs.getString("field_1"));
dto.setField_2(rs.getString("field_2"));
dto.setField_3(rs.getString("field_3"));
return dto;
}
}
In this example TableDto is real class with getters and setters.
Usually during my work hours i spend a lot of time querying the db(oracle) and parsing blob from various table where the streams that we receive are stored.
There are various type of stream so i was trying to made a simple webapp where i write the select statement and it returns all the stream parsed accordingly.
My problem is that using jpa and executing the simple native query:
select B_BODY from TABLE_B where TRANSACTION_ID = 'GG-148c-01502790743907855009';
the statement doesn't return anything but querying directly the database return the record.
this is my java code:
#Transactional(readOnly = true)
public List<Object[]> retrieveBlobs(String squery) {
squery = squery + " and rownum <= "+maxResults;
Query query = em.createNativeQuery(squery);
List<Object[]> resultList = query.getResultList();
return resultList;
}
this is the sql generated:
Hibernate:
select
B_BODY
from
TABLE_B
where
TRANSACTION_ID ='GG-148c-01502790743907855009'
and rownum <= 100
i know that this way might seems weird but our team spend a lot of time trying to tokenize the stored streams(the code that identify how to parse the stream is also stored in the tables).Useless to say this application is going to be used only internally.there is a way to just execute the query as it is and retrieve the correct output?
Well, I tried to reproduce your problem on MariaDB (with mysql-connector-java + hibernate) but selecting a lob with native query was working properly.
You can try to create entities which will be holding your blob and check if this would help. Just make a standard entity with #Lob annotation over your lob column.
#Entity
#NamedQueries(
#NamedQuery(name = FIND_ALL, query = "SELECT m FROM LobEntity m")
)
public class LobEntity {
public static final String FIND_ALL = "PhpEntity.findAll";
#Id
#Column(name = "id")
private String id;
#Lob
#Column(name = "lob")
private byte[] lob;
//Use Blob class if you want to use streams.
//#Column(name = "lob")
//#Lob
//private Blob lob;
}
I have the following HQL statement:
select d.model, v.vendor from Device d, Vendor v where d.vendorId = v.id
and the following java code:
private List<Device> allDevices;
//Getter and Setter are created
public List<Device> getAllDevices() {
return allDevices;
}
public void setAllDevices(List<Device> allDevices) {
this.allDevices = allDevices;
}
public List<Device> readDevices() {
session = HibernateUtil.getSessionFactory().openSession();
String hql = "select d.model, v.vendor from Device d, Vendor v where d.vendorId = v.id";
Query query = session.createQuery(hql);
List list = query.list();
allDevices = new ArrayList();
//Here comes the code, loop, for getting the values from the list !?!
[...]
session.close();
return allDevices;
}
My Question is: How can I get the values from query.list() and add them to the allDevices ArrayList:
The class Device is a mapping class of the MySQL DB "device" table and has string column model and Integer column vendor_id. The vendor_id is the id of the "vendor" table. The "vendor" table has Integer column id and string column vendorname. I would like to show on the JSF page the model name and the corresponding vendor name instead of the vendor id.
My first attempt with the following loop is not working:
for (int i = 0; i < list.size(); i++) {
device = (Device) list.get(i);
allDevices.add(device);
}
Can anyone help me out?
I suggest using JPA instead of plain hibernate, then you can use a TypedQuery and you are using standards. Should by quite easy to make the switch and you can then drop your HibernateUtil class
#PersistenceContext
private EntityManager em;
public List<Device> readDevices() {
String hql = "select d.model, v.vendor from Device d, Vendor v where d.vendorId = v.id";
TypedQuery<Device> query = em.createQuery(hql, Device.class);
allDevices.addAll(query.getResultList());
return allDevices;
}
Also you probably don't want this code in your JSF backed bean but in a service or repository class instead.