Hibernate update query - java

Any one tell me the HQL for this SQL code
UPDATE ModelClassname SET ClassVariablename=ClassVariablename+10 WHERE ClassVariableId=001;

There is no point using HQL to do that, you can use direct SQL if you want to do that, through a JDBC query (or even through a Hibernate query, you can use SQL queries).
Using HQL queries to update is only recommended when doing batch updates, not a single row.
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-direct
A more object-oriented way would be to load your object using HQL, do what you need to do in the Java world (columnValue +=10, whatever else you need to do), and then persist it back using hibernate session flush.
I suppose it involves more operations so it's less efficient (in pure performance) but depending on your Hibernate configuration (caching, clustering, second-level cache, etc.) it could be a lot better. Not to mention more testable, of course.

As others say, there is better ways, but if you really have to, then for example with following syntax:
update EntityName m set m.salary = m.salary +10 where m.id = 1

In addition to Adam Batkin's answer, I would like to add that such queries are generally not used (except if you need to modify a whole loat of rows at once) in Hibernate. The goal of Hibernate is to work with objects. So you generally do:
MyEntity m = (MyEntity) session.get(MyEntity.class, "001");
m.setValue(m.getValue() + 10);
// and the new value will automatically be written to database at flush time

The HQL query should look pretty similar, except instead of using table and column names, you should use the entity and property names (i.e. whatever you use in Java).

Please try this one
Query q = session.createQuery("from ModelClassname where ClassVariableId= :ClassVariableId");
q.setParameter("ClassVariableId", 001);
ModelClassname result = (ModelClassname)q.list().get(0);
Integer i = result.getClassVariableName();
result.setClassVariableName(i+10);
session.update(result);
With Regards,
Lavanyavathi.Bharathidhasan

HQL will help you here with bringing object to you with its session's help that you can update easily.
//id of employee that you want to update
int updatedEmployeeID = 6;
//exact employee that you want to update
Employee updateEmployee = session.get(Employee.class, updatedEmployeeID);
//for debug to see is that exact data that you want to update
System.out.println("Employee before update: "+updateEmployee);
//basically we use setter to update from the #Entity class
updateEmployee.setCompany("Arthur House");
//commit
session.getTransaction().commit();

Related

Why does Hibernate throw a QuerySyntaxException for this HQL?

While building a query using Hibernate, I noticed something rather odd. If I use sequential named parameters for the ORDER BY clause, Hibernate throws a QuerySyntaxException (the colon prefix being an unexpected token):
createQuery("FROM MyEntity ORDER BY :orderProperty :orderDirection");
However, when this is done with a plain SQL query the query is created without a problem:
createSQLQuery("SELECT * FROM my_entity_table ORDER BY :orderProperty :orderDirection");
I know Hibernate is doing more String evaluation for the HQL query, which is probably why the SQL query is created without an error. I am just wondering why Hibernate would care that there are two sequential named parameters.
This isn't a huge issue since it is simple to work around (can just append the asc or desc String value to the HQL instead of using a named paramater for it), but it struck my curiosity why Hibernate is preventing it (perhaps simply because 99% of the time sequential named parameters like this result in invalid SQL/HQL).
I've been testing this in my local, and I can't get your desired outcome to work with HQL.
Here is quote from the post I linked:
You can't bind a column name as a parameter. Only a column value. This name has to be known when the execution plan is computed, before binding parameter values and executing the query. If you really want to have such a dynamic query, use the Criteria API, or some other way of dynamically creating a query.
Criteria API looks to be the more useful tool for your purposes.
Here is an example:
Criteria criteria = session.createCriteria(MyEntity.class);
if (orderDirection.equals("desc")) {
criteria.addOrder(Order.desc(orderProperty));
}
else {
criteria.addOrder(Order.asc(orderProperty));
}
According to the answer accepted in this question, you can only define parameters in WHERE and HAVING clauses.
The same answer also gives you some ways to have a workaround for your problem, however I will add one more way to do this:
Use the CASE - WHEN clause in your ORDER BY, this would work by the following way:
SELECT u FROM User u
ORDER BY
CASE WHEN '**someinputhere**' = :orderProperty
AND '**someotherinput**' = :orderDirection
THEN yourColumn asc
ELSE yourColumn desc END
Please, note that in this approach would required you to write all the possible inputs for ordering. Not really beautiful but really useful, especially because you would not need to write multiple queries with different orderings, plus with this approach you can use NamedQueries, which would be possible by writing the query dinamically using string concats.
Hope this can solve your problem, good luck!

Update query performance with Hibernate

We are examining 2 different methods to do our entities updates:
"Standard" updates - Fetch from DB, set Fields, persist.
We have a Query for each entity that looks like this:
String sqlQuery = "update Entity set entity.field1 = entity.field1, entity.field2 = entity.field2, entity.field3 = entity.field3, .... entity.fieldn = entity.fieldn"
We receive the fields that changed (and their new values) and we replace the string fields (only those required) with the new values. i.e. something like :
for each field : fields {
sqlQuery.replace(field.fieldName, getNewValue(field));
}
executeQuery(sqlQuery);
Any ideas if these options differ in performance to a large extent? Is the 2nd option even viable? what are the pros / cons?
Please ignore the SQL Injection vulnerability, the example above is only an example, we do use PreparedStatements for the query building.
And build a mix solution?
First, create a hasmap .
Second, create a new query for a PreparedStament using before hasmap (for avoid SQL injection)
Third, set all parameters.
The O(x)=n, where n is the number of parameters.
The first solution is much more flexible You can rely on Hibernate dirty checking mechanism for generating the right updates. That's one good reason why an ORM tool is great when writing data.
The second approach is no way way better because it might generate different update plans, hence you can't reuse the PreparedStatement statement cache across various column combinations. Instead of using string based templates (vulnerable to SQL injections) you could use JOOQ instead. JOOQ allows you to reference your table columns in Java, so you can build the UPDATE query in a type-safe fashion.

Hibernate - distinct results with pagination

This seems to be a well known problem for years as can be read here:
http://blog.xebia.com/2008/12/11/sorting-and-pagination-with-hibernate-criteria-how-it-can-go-wrong-with-joins/
And even finds reference in hibernate faqs:
https://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_does_not_return_distinct_results_for_a_query_with_outer_join_fetching_enabled_for_a_collection_even_if_I_use_the_distinct_keyword
This has also been discussed previously on SO
How to get distinct results in hibernate with joins and row-based limiting (paging)?
The problem is that even after going through all these resources, I have not been able to resolve my issue, which seems to be a little different from this standard problem, although I am not sure.
The standard solution proposed here involves creating two queries, first one for getting distinct IDs and then using those in a higher level query to get the desired pagination. The hibernate classes in my case are something like
A
- aId
- Set<B>
B
- bId
It appears to me that the subquery seems to be working fine for me and is being able to get the distinct aIds but the outer query which is supposed to do the pagination is again fetching the duplicates and thus the distinct in subquery is having no effect.
Assuming I have one A object which has a set of four B objects, My analysis is that because of introduction of set, while fetching data for
session.createCriteria(A.class).list();
hibernate is populating four references in the list pointing to just one object. Because of this the standard solution is failing for me.
Could someone please help in coming up with a solution for this case?
Edit: I have decided to go for doing pagination by ourselves from the distinct resultset. The other equally bad way could have been to lazy load the B objects but that would have required separate queries for all the A objects to fetch corresponding B objects
Consider using DistinctRootEntity result transformer like this
session.createCriteria(A.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
UPDATE
The samples of queries for one-to-many associations.
public Collection<Long> getIDsOfAs(int pageNumber, int pageSize) {
Session session = getCurrentSession();
Criteria criteria = session.createCriteria(A.class)
.setProjection(Projections.id())
.addOrder(Order.asc("id"));
if(pageNumber >= 0 && pageSize > 0) {
criteria.setMaxResults(pageSize);
criteria.setFirstResult(pageNumber * pageSize);
}
#SuppressWarnings("unchecked")
Collection<Long> ids = criteria.list();
return ids;
}
public Collection<A> getAs(int pageNumber, int pageSize) {
Collection<A> as = Collections.emptyList();
Collection<Long> ids = getIDsOfAs(pageNumber, pageSize);
if(!ids.isEmpty()) {
Session session = getCurrentSession();
Criteria criteria = session.createCriteria(A.class)
.add(Restrictions.in("id", ids))
.addOrder(Order.asc("id"))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
#SuppressWarnings("unchecked")
as = criteria.list();
}
return as;
}
You mention the reason you're seeing this problem is because Set<B> is fetched eagerly. If you're paginating, chances are you don't need the B's for each A, so it might be better to fetch them lazily.
However, this same problem occurs when you join the B's into the query to make a selection.
In some cases, you will not only want to paginate, but also sort on other fields than the ID. I think the way to do this is to formulate the query like this:
Criteria filter = session.createCriteria(A.class)
.add(... any criteria you want to filter on, including aliases etc ...);
filter.setProjection(Projections.id());
Criteria paginate = session.createCriteria(A.class)
.add(Subqueries.in("id", filter))
.addOrder(Order.desc("foo"))
.setMaxResults(max)
.setFirstResult(first);
return paginate.list();
(pseudocode, didn't check if the syntax is exactly right but you get the idea)
I answered this here: Pagination with Hibernate Criteria and DISTINCT_ROOT_ENTITY
You need to do 3 things, 1) get the total count, 2) get the ids of the rows you want, and then 3) get your data for the ids found in step 2. It is really not all that bad once you get the order correct, and you can even create a generic method and send it a detached criteria object to make it more abstract.
I used groupBy property to achieve this. Hope it works.
Criteria filter = session.createCriteria(A.class);
filter.setProjection(Projections.groupProperty("aId"));
//filter.add(Restrictions.eq()); add restrictions if any
filter.setFirstResult(pageNum*pageSize).setMaxResults(pageSize).addOrder(Order.desc("aId"));
Criteria criteria = session.createCriteria(A.class);
criteria.add(Restrictions.in("aId",filter.list())).addOrder(Order.desc("aId"));
return criteria.list();

Inject attribute into JPQL SELECT clause

Let's depict the following use case: I have a JPQL Query which on the fly creates data objects using the new keyword. In the SELECT clause I would like to inject an attribute which is not known to the database but to the layer which queries it.
This could look like
EntityManager em; // Got it from somewhere
boolean editable = false; // Value might change, e.g. depending on current date
Query q = em.createQuery("SELECT new foo.bar.MyDTO(o, :editable) FROM MyObject o")
.setParameter("editable", editable);
List<MyDTO> results = (List<MyDTO>) q.getResultList();
Any ideas how this kind of attribute or parameter injection into the SELECT clause might work in JPQL? Both JPA and JPA 2.0 solutions are applicable.
Edit: Performance does not play a key role, but clarity and cleanness of code.
Have you measured a performance problem when simply iterating over the list of results and call a setter on each of the elements. I would guess that compared to
the time it takes to execute the query over the database (inter-process call, network communication)
the time it takes to transform each row into a MyObject instance using reflection
the time it takes to transform each MyObject instance into a MyDTO using reflection
your loop will be very fast.
If you're so concerned about performance, you should construct your MyDTO instances manually from the returned MyObject instances instead of relying on Hibernate and reflection to do it.
Keep is simple, safe, readable and maintainable first. Then, if you have a performance problem, measure to detect where it comes from. Then and only then, optimize.
It will not work without possible vendor extensions, because according specification:
4.6.4 Input Parameters
...
Input parameters can only be used in the
WHERE clause or HAVING clause of a query.

Designing Java Object for SQL Query

Are there any good utils/frameworks which could generate Java Object for SQL Query?
QueryDsl automatically creates Query Objects from your Hibernate, JPA or JDO classes, but also from your DB schema.
Querying with Querydsl SQL is as
simple as this :
QCustomer customer = new QCustomer("c");
SQLTemplates dialect = new HSQLDBTemplates(); // SQL-dialect
SQLQuery query = new SQLQueryImpl(connection, dialect);
List<String> lastNames = query.from(customer)
.where(customer.firstName.eq("Bob"))
.list(customer.lastName);
It also supports subqueries:
To create a subquery you create a
SQLSubQuery instance, define the query
parameters via from, where etc and use
unique or list to create a subquery,
which is just a type-safe Querydsl
expression for the query. unique is
used for a unique (single) result and
list for a list result.
query.from(customer).where(
customer.status.eq(
new SQLSubQuery().from(customer2).unique(customer2.status.max()))
.list(customer.all())
Another example
query.from(customer).where(
customer.status.in(new SQLSubQuery().from(status).where(
status.level.lt(3)).list(status.id))
.list(customer.all())
I don't know its gonna be enough helpful but, as you asked for utils, I would suggest you to read about the QUERY OBJECT PATTERN (P of EAA, M. Fowler), if you have time to implement something, its a good beginning, otherwise you may lookfor any ORM framework.
I am using torque to do that. There is an example(Tutorial) which show what it can do at http://db.apache.org/torque/releases/torque-3.3/tutorial/step5.html
But what exactly is it you want? Do you just a simple way to serialize/unserialize objects to the database, and load them based on a primary/foreign key, or do you need to issue really complicated queries?

Categories

Resources