Calculate procedures or queries in hibernate in my entitys - java

I have a table called "Endoso", this table has the properties of "id", "numEndoso","endosos_por_dia". The "numEndoso" is the id of the envio(id of table EnvioRemesa), and the "endosos_por_dia" property is a calculated property as I put below.
select count(*)
from documento d
inner join remesa r
on r.id = d.remesa_id
inner join envio_remesa er
on r.id = er.remesa_id
where r.id=?
What I want and can't do, is that for example when I calculate endosos_por_dia if 8 documents turn out, create 8 different records in my database, increasing from 1 to 8.And how could I put my calculated property query on my entity Endoso and it will be reflected in the database? How can I do this in hibernate?

You can use a Formula:
#Formula("(select count(*) ... where r.id=numEndoso)")
public int getEndososPorDia() {
return endososPorDia;
}
Note that numEndoso in the SQL fragment refers to the ID of your entity, you might need to adapt it because I assumed that it was the name of the column.
This will make the endososPorDia field read-only as far as Hibernate is concerned, you will need to modify the underlying data (add new documents) and then refresh the entity to update the value

Related

Spring custom #Query with incrementable variable

I have a query that map to a Custom Object :
#Query("SELECT new com.mypackage.CmcXml(c.nom, c.prenom, c.genre "+
"FROM Cmc c")
List<CmcXml> getExportCmc();
So I get this kind of result :
{"NOM1", "PRENOM1", "GENRE1"},
{"NOM2", "PRENOM2", "GENRE2"},
{"NOM3", "PRENOM3", "GENRE3"}
I would like to have an counter that increment while retrieving the data :
#Query("SELECT new com.mypackage.CmcXml(myCounter, c.nom, c.prenom, c.genre "+
"FROM Cmc c")
List<CmcXml> getExportCmc();
The result I want :
{1, "NOM1", "PRENOM1", "GENRE1"},
{2, "NOM2", "PRENOM2", "GENRE2"},
{3, "NOM3", "PRENOM3", "GENRE3"}
Is it possible to do it in the #Query or do I have to go through all the list after the request ?
No , row number is not supported in jpa/hibernate. you have to use native query.
This is not possible in JPA as JPA operates to entities and entities are in turn mapped to tables in database. Row number corresponds to a result set and not actually exists in database table.
You can try something as below using native query depends on your database.
SELECT #rownumber\\:=#rownumber+1 as rownumber, column From Table
Or as JB Nizet suggested in comments, you can use your own logic to map those objects to objects with counter.

How to force Hibernate use AND in update query?

I am trying to update a raw by composite primary key by using hibernate.
Hibernate uses the next style for such updates:
update mytable set mycolumn=321 where (left_pk, right_pk) = (123, 456);
Is it possible to force hibernate to use the next style?:
update mytable set mycolumn=321 where left_pk = 123 and right_pk = 456;
Both queries work but with a huge difference (at least in MariaDB).
If we use repeatable read transaction then the first query locks the whole table for updates and the second query locks only the single row for updates.
I would prefer to lock only a single row, so I need to use the second query.
You can go for NamedQueries approach in Hibernate,
For example:
//Create Query
#NamedQueries({ #NamedQuery(name = " YOUR QUERY NAME",
query = "from DeptEmployee where department = :department and emp = :emp") })
// set multiple parameters
query.setParameter("department",department)
.setParameter("emp", emp)
Try giving this a shot.

How to delete multiple rows from multiple tables using Where clause?

Using an Oracle DB, I need to select all the IDs from a table where a condition exists, then delete the rows from multiple tables where that ID exists. The pseudocode would be something like:
SELECT ID FROM TABLE1 WHERE AGE > ?
DELETE FROM TABLE1 WHERE ID = <all IDs received from SELECT>
DELETE FROM TABLE2 WHERE ID = <all IDs received from SELECT>
DELETE FROM TABLE3 WHERE ID = <all IDs received from SELECT>
What is the best and most efficient way to do this?
I was thinking something like the following, but wanted to know if there was a better way.
PreparedStatement selectStmt = conn.prepareStatment("SELECT ID FROM TABLE1 WHERE AGE > ?");
selectStmt.setInt(1, age);
ResultSet rs = selectStmt.executeQuery():
PreparedStatement delStmt1 = conn.prepareStatment("DELETE FROM TABLE1 WHERE ID = ?");
PreparedStatement delStmt2 = conn.prepareStatment("DELETE FROM TABLE2 WHERE ID = ?");
PreparedStatement delStmt3 = conn.prepareStatment("DELETE FROM TABLE3 WHERE ID = ?");
while(rs.next())
{
String id = rs.getString("ID");
delStmt1.setString(1, id);
delStmt1.addBatch();
delStmt2.setString(1, id);
delStmt2.addBatch();
delStmt3.setString(1, id);
delStmt3.addBatch();
}
delStmt1.executeBatch();
delStmt2.executeBatch();
delStmt3.executeBatch();
Is there a better/more efficient way?
You could do it with one DELETE statement if two of your 3 tables (for example "table2" and "table3") are child tables of the parent table (for example "table1") that have a "ON DELETE CASCADE" option.
This means that the two child tables have a column (example column "id" of "table2" and "table3") that has a foreign key constraint with "ON DELETE CASCADE" option that references the primary key column of the parent table (example column "id" of "table1"). This way only deleting from the parent table would automatically delete associated rows in the child tables.
Check out this in more detail : http://www.techonthenet.com/oracle/foreign_keys/foreign_delete.php
If you delete only few records of a large tables ensure that an index on the
column ID is defined.
To delete the records from the table TABLE2 and 3 the best strategy is to use the CASCADE DELETE as proposed by
#ivanzg - if this is not possible, see below.
To delete from TABLE1 a far superior option that a batch delete on a row basis, use signle delete using the age based predicate:
PreparedStatement stmt = con.prepareStatement("DELETE FROM TABLE1 WHERE age > ?")
stmt.setInt(1,60)
Integer rowCount = stmt.executeUpdate()
If you can't cascade delete, use for the table2 and 3 the same concept as above but with the following statment:
DELETE FROM TABLE2/*or 3*/ WHERE ID in (SELECT ID FROM TABLE1 WHERE age > ?)
General best practice - minimum logic in client, whole logic in the database server. The database should be able to do reasonable execution plan
- see the index note above.
DELETE statement operates a table per statement. However the main implementations support triggers or other mechanisms that perform subordinate modifications. For example Oracle's CREATE TRIGGER.
However developers might end up figuring out what is the database doing behind their backs. (When/Why to use Cascading in SQL Server?)
Alternatively, if you need to use an intermediate result in your delete statements. You might use a temporal table in your batch (as proposed here).
As a side note, I see not transaction control (setAutoCommit(false) ... commit() in your example code. I guess that might be for the sake of simplicity.
Also you are executing 3 different delete batches (one for each table) instead of one. That might negate the benefit of using PreparedStatement.

how to write raw play queries for a table which is not mapped to an entity

I am using play framework for the first time and I need to link objects of the same type. In order to do so I have added a self referencing many to many relationship like this:
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="journal_predecessor", joinColumns={#JoinColumn(name="journal_id")}, inverseJoinColumns={#JoinColumn(name="predecessor_id")})
public List<Journal> journalPredecessor = new ArrayList<Journal>();
I obtain the table journal_predecessor which contains the two columns: journal_id and predecessor_id, both being FKs pointing to the primary key of the table journal.
My question is how can I query this table using raw queries if I am using H2 in-memory database. thanks!
Actually it was very easy. I just needed to create an instance of SqlQuery to create a raw query:
SqlQuery rawQuery = Ebean.createSqlQuery("SELECT journal_id from journal_predecessor where journal_id=" + successorId + " AND predecessor_id=" + predecessorId);
And because i just needed to check weather a row exists or not, I find the size of the set of the results returned by the query:
Set<SqlRow> sqlRow = rawQuery.findSet();
int rowExists = sqlRow.size();

How to convert nested SQL to HQL

I am new to the Hibernate and HQL. I want to write an update query in HQL, whose SQL equivalent is as follows:
update patient set
`last_name` = "new_last",
`first_name` = "new_first"
where id = (select doctor_id from doctor
where clinic_id = 22 and city = 'abc_city');
doctor_id is PK for doctor and is FK and PK in patient. There is one-to-one mapping.
The corresponding Java classes are Patient (with fields lastName, firstName, doctorId) and Doctor (with fields doctorId).
Can anyone please tell what will be the HQL equivalent of the above SQL query?
Thanks a lot.
String update = "update Patient p set p.last_name = :new_last, p.first_name = :new_first where p.id = some (select doctor.id from Doctor doctor where doctor.clinic_id = 22 and city = 'abc_city')";
You can work out how to phrase hql queries if you check the specification. You can find a section about subqueries there.
I don't think you need HQL (I know, you ask that explicitly, but since you say you're new to Hibernate, let me offer a Hibernate-style alternative). I am not a favor of HQL, because you are still dealing with strings, which can become hard to maintain, just like SQL, and you loose type safety.
Instead, use Hibernate criteria queries and methods to query your data. Depending on your class mapping, you could do something like this:
List patients = session.CreateCriteria(typeof(Patient.class))
.createAlias("doctor", "dr")
.add(Restrictions.Eq("dr.clinic_id", 22))
.add(Restrictions.Eq("dr.city", "abc_city"))
.list();
// go through the patients and set the properties something like this:
for(Patient p : patients)
{
p.lastName = "new lastname";
p.firstName = "new firstname";
}
Some people argue that using CreateCriteria is difficult. It takes a little getting used to, true, but it has the advantage of type safety and complexities can easily be hidden behind generic classes. Google for "Hibernate java GetByProperty" and you see what I mean.
update Patient set last_name = :new_last , first_name = :new_first where patient.id = some(select doctor_id from Doctor as doctor where clinic_id = 22 and city = abc_city)
There is a significant difference between executing update with select and actually fetching the records to the client, updating them and posting them back:
UPDATE x SET a=:a WHERE b in (SELECT ...)
works in the database, no data is transferred to the client.
list=CreateCriteria().add(Restriction).list();
brings all the records to be updated to the client, updates them, then posts them back to the database, probably with one UPDATE per record.
Using UPDATE is much, much faster than using criteria (think thousands of times).
Since the question title can be interpreted generally as "How to use nested selects in hibernate", and the HQL syntax restricts nested selects only to be in the select- and the where-clause, I would like to add here the possibility to use native SQL as well. In Oracle - for instance - you may also use a nested select in the from-clause.
Following query with two nested inner selects cannot be expressed by HQL:
select ext, count(ext)
from (
select substr(s, nullif( instr(s,'.', -1) +1, 1) ) as ext
from (
select b.FILE_NAME as s from ATTACHMENT_B b
union select att.FILE_NAME as s from ATTACHEMENT_FOR_MAIL att
)
)
GROUP BY ext
order by ext;
(which counts, BTW, the occurences of each distinct file name extension in two different tables).
You can use such an sql string as native sql like this:
#Autowired
private SessionFactory sessionFactory;
String sql = ...
SQLQuery qry = sessionFactory.getCurrentSession().createSQLQuery(sql);
// provide an appropriate ResultTransformer
return qry.list();

Categories