hibernate java select queries - java

i am new to this and today i tried to play hibernate with a method that returns the result of selected row...if is selected then it can return the result in int.. here is my method
public int validateSub(String slave, String source, String table){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Query q = session.createQuery("from Subscribers where slave = :slave AND source = :source AND tbl = :tbl");
q.setParameter("slave", slave);
q.setParameter("source", source);
q.setParameter("tbl", table);
int result = q.executeUpdate();
return result;
}
from this method i tried to validate the 3 values that i get from the Subscribers table but at the end i tried to compile having this error
Exception in thread "Thread-0" org.hibernate.hql.QueryExecutionRequestException: Not supported for select queries [from com.datadistributor.main.Subscribers where slave = :slave AND source = :source AND tbl = :tbl]

You can have a look at the below links that how executeUpdate works, one is from the hibernate docs and other the java docs for JPA which defines when the exception is thrown by the method
http://docs.oracle.com/javaee/6/api/javax/persistence/Query.html#executeUpdate()
https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/Query.html#executeUpdate()
Alternatively you can use
List list = query.list();
int count = list != null ? list.size() : 0;
return count;

you are running a select query, Eventhough you are not using the select keyword here hibernate will add that as part of the generated SQL.
what you need to do to avoid the exception is the say
q.list();
now, this will return a List (here is the documentation).
if you are trying to get the size of the elements you can say
Query q = session.createQuery("select count(s) from Subscribers s where slave = :slave AND source = :source AND tbl = :tbl");
Long countOfRecords = (Long)q.list().get(0);
you can execute update statements as well in HQL, it follows a similar structure as SQL (except with object and properties).
Hope this helps.

here you want to select record so it is posible without select key word
sessionFactory sesionfatory;
ArrayList list = (ArrayList)sessionfactory.getCurruntSession().find(from table where name LIKE "xyz");
long size = list.get(0);

I also happened to make the same mistake today.
Your SQL statement is not correct.
You can try:
DELETE from Subscribers WHERE slave = :slave AND source

Try this:
int result = q.list().size();

Related

How to fetch list of tables in database using HibernateDaoSupport?

Here I have added my code. Issue occurs in try block while I am trying fetch list of tables.
Database is MySql
Exception is : java.lang.IllegalArgumentException: node to traverse cannot be null!
public class DBOptimizationDAO extends HibernateDaoSupport {
private static final Log log = LogFactory.getLog(DBOptimizationDAO.class);
public void optimizeAdapter(String year)
{
List<com.ecw.adapterservice.beans.TransactionInbound> transactionInboundList = null;
StringBuilder queries = new StringBuilder();
try {
transactionInboundList = (List<com.ecw.adapterservice.beans.TransactionInbound>)super.getHibernateTemplate().find("from TransactionInbound where inboundTimestamp < '" + year+ "-01-01'order by 1 desc limit 2");
// Check if archive table exist or not
List<Object> inboundObj = getHibernateTemplate().find("SHOW TABLES LIKE transaction_outbound");
List<Object> outboundObj = getHibernateTemplate().find("SHOW TABLES LIKE 'transaction_outbound_archive'");
The HibernateTemplate::find expects a HQL query in the string parameter and you are passing a native statement. You can do native stuff (queries, statements, etc) using the Session object returned by HibernateTemplate::getSession. To pass a native select query you then have Session::createSQLQuery
BUT do you really want to rely on database specific code to do this? There is a more elegant way to do it by using DatabaseMetaData::getTables. See this answer. And you can get an instance of DatabaseMetaData from a callback method of your HibernateTemplate.
Try this:
Session session = getHibernateTemplate().getSessionFactory().getCurrentSession();
if(!session instaceof SessionImpl){
//handle this, maybe throw an exception
}
else {
Connection con = (SessionImpl)session.connection();
...
}

Hibernate is 1000 times slower than sql query

I have this setup
#Table(name ="A")
EntityA {
Long ID;
List<EntityB> children;
}
#Table(name ="B")
EntityB {
Long ID;
EntityA parent;
EntityC grandchild;
}
#Table(name ="C")
EntityC {
Long ID;
}
The SQL query is this (I omitted irrelevant details):
select top 300 from A where ... and ID in (select parent from B where ... and grandchild in (select ID from C where ...)) order by ...
The sql query in direct database or through Hibernate (3.5) SQL runs 1000 faster than using Criteria or HQL to express this.
The SQL generated is identical from HQL and Criteria and the SQL I posted there.
[EDIT]: Correction - the sql was not identical. I didn't try the Hibernate style parameter setting on the management studio side because I did not realize this until later - see my answer.
If I separate out the subqueries into separate queries, then it is fast again.
I tried
removing all mappings of child, parent, ect.. and just use Long Id references - same thing, so its not a fetching, lazy,eager related.
using joins instead of subqueries, and got the same slow behaviour with all combinations of fetching and loading.
setting a projection on ID instead of retrieving entities, so there is no object conversion - still slow
I looked at Hibernate code and it is doing something astounding. It has a loop through all 300 results that end up hitting the database.
private List doQuery(
final SessionImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws SQLException, HibernateException {
final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = hasMaxRows( selection ) ?
selection.getMaxRows().intValue() :
Integer.MAX_VALUE;
final int entitySpan = getEntityPersisters().length;
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
// would be great to move all this below here into another method that could also be used
// from the new scrolling stuff.
//
// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
// that I could do the control breaking at the means to know when to stop
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final List results = new ArrayList();
try {
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
if ( log.isTraceEnabled() ) log.trace( "processing result set" );
int count;
for ( count = 0; count < maxRows && rs.next(); count++ ) {
if ( log.isTraceEnabled() ) log.debug("result set row: " + count);
Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies
);
results.add( result );
if ( createSubselects ) {
subselectResultKeys.add(keys);
keys = new EntityKey[entitySpan]; //can't reuse in this case
}
}
if ( log.isTraceEnabled() ) {
log.trace( "done processing result set (" + count + " rows)" );
}
}
finally {
session.getBatcher().closeQueryStatement( st, rs );
}
initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) );
if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );
return results; //getResultList(results);
}
In this code
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
it hits the database with the full SQL, but there are no results collected anywhere.
Then it proceeds to go through this loop
for ( count = 0; count < maxRows && rs.next(); count++ ) {
Where for every one of the expected 300 results, it ends up hitting the database to get the actual result.
This seems insane, since it should already have all the results after 1 query. Hibernate logs do not show any additional SQL being issued during all that time.
Anyone have any insight? The only option I have is to go to native SQL query through Hibernate.
I finally managed to get to the bottom of this. The problem was being caused by Hibernate setting the parameters separately from the actual SQL query that involved subqueries. So native SQL or not, the performance will be slow if this is done. For example this will be slow:
String sql = some sql that has named parameter = :value
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.setParameter ("value", someValue);
List<Object[]> list = (List<Object[]>)sqlQuery.list();
And this will be fast
String sql = some native sql where parameter = 'actualValue'
SQLQuery sqlQuery = session.createSQLQuery(sql);
List<Object[]> list = (List<Object[]>)sqlQuery.list();
It seems that for some reason with letting Hibernate take care of the parameters it ends up getting stuck in the resultSet fetching. This is probably because the underlying query on the database is taking much longer being parameterized. I ended up writing the equivalent of Hibernate Criteria and Restrictions code that sets the parameters directly as above.
We noticed a similar behaviour in our system.
And also encountered that writing the query with hardcoded parameters instead of using setParameter() would fixed the issue.
We are using MS SQL Server and after further investigation we noticed the the root cause of our issue is a default configuration of the sql server driver that transmits the query parameters as unicode. This lead to our indices being ignored since they were based on the ascii values on the queried columns.
The solution was to setup this property in the jdbc url : sendStringParametersAsUnicode=false
More details can be found here.
https://stackoverflow.com/a/32867579

Ebean query using setDistinct() does not work

I'm using an ebean query in the play! framework to find a list of records based on a distinct column. It seems like a pretty simple query but the problem is the ebean method setDistinct(true) isn't actually setting the query to distinct.
My query is:
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findList();
In my results I get duplicate artist names.
From what I've seen I believe this is the correct syntax but I could be wrong. I'd appreciate any help. Thank you.
I just faced the same issue out of the blue and can not figure it out. As hfs said its been fixed in a later version but if you are stuck for a while you can use
findSet()
So in your example use
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findSet();
According to issue #158: Add support for using setDistinct (by excluding id property from generated sql) on the Ebean bug tracker, the problem is that an ID column is added to the beginning of the select query implicitly. That makes the distinct keyword act on the ID column, which will always be distinct.
This is supposed to be fixed in Ebean 4.1.2.
As an alternative you can use a native SQL query (SqlQuery).
The mechanism is described here:
https://ebean-orm.github.io/apidocs/com/avaje/ebean/SqlQuery.html
This is from the documentation:
public interface SqlQuery
extends Serializable
Query object for performing native SQL queries that return SqlRow's.
Firstly note that you can use your own sql queries with entity beans by using the SqlSelect annotation. This should be your first approach when wanting to use your own SQL queries.
If ORM Mapping is too tight and constraining for your problem then SqlQuery could be a good approach.
The returned SqlRow objects are similar to a LinkedHashMap with some type conversion support added.
// its typically a good idea to use a named query
// and put the sql in the orm.xml instead of in your code
String sql = "select id, name from customer where name like :name and status_code = :status";
SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
sqlQuery.setParameter("name", "Acme%");
sqlQuery.setParameter("status", "ACTIVE");
// execute the query returning a List of MapBean objects
List<SqlRow> list = sqlQuery.findList();
i have a solution for it:-
RawSql rawSql = RawSqlBuilder
.parse("SELECT distinct CASE WHEN PARENT_EQUIPMENT_NUMBER IS NULL THEN EQUIPMENT_NUMBER ELSE PARENT_EQUIPMENT_NUMBER END AS PARENT_EQUIPMENT_NUMBER " +
"FROM TOOLS_DETAILS").create();
Query<ToolsDetail> query = Ebean.find(ToolsDetail.class);
ExpressionList<ToolsDetail> expressionList = query.setRawSql(rawSql).where();//ToolsDetail.find.where();
if (StringUtils.isNotBlank(sortBy)) {
if (StringUtils.isNotBlank(sortMode) && sortMode.equals("descending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
//expressionList.orderBy().asc(sortBy);
}else if (StringUtils.isNotBlank(sortMode) && sortMode.equals("ascending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"asc");
// expressionList.orderBy().asc(sortBy);
} else {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
}
}
if (StringUtils.isNotBlank(fullTextSearch)) {
fullTextSearch = fullTextSearch.replaceAll("\\*","%");
expressionList.disjunction()
.ilike("customerSerialNumber", fullTextSearch)
.ilike("organizationalReference", fullTextSearch)
.ilike("costCentre", fullTextSearch)
.ilike("inventoryKey", fullTextSearch)
.ilike("toolType", fullTextSearch);
}
//add filters for date range
String fromContractStartdate = Controller.request().getQueryString("fm_contract_start_date_from");
String toContractStartdate = Controller.request().getQueryString("fm_contract_start_date_to");
String fromContractEndtdate = Controller.request().getQueryString("fm_contract_end_date_from");
String toContractEnddate = Controller.request().getQueryString("fm_contract_end_date_to");
if(StringUtils.isNotBlank(fromContractStartdate) && StringUtils.isNotBlank(toContractStartdate))
{
Date fromSqlStartDate=new Date(AppUtils.convertStringToDate(fromContractStartdate).getTime());
Date toSqlStartDate=new Date(AppUtils.convertStringToDate(toContractStartdate).getTime());
expressionList.between("fmContractStartDate",fromSqlStartDate,toSqlStartDate);
}if(StringUtils.isNotBlank(fromContractEndtdate) && StringUtils.isNotBlank(toContractEnddate))
{
Date fromSqlEndDate=new Date(AppUtils.convertStringToDate(fromContractEndtdate).getTime());
Date toSqlEndDate=new Date(AppUtils.convertStringToDate(toContractEnddate).getTime());
expressionList.between("fmContractEndDate",fromSqlEndDate,toSqlEndDate);
}
PagedList pagedList = ToolsQueryFilter.getFilter().applyFilters(expressionList).findPagedList(pageNo-1, pageSize);
ToolsListCount toolsListCount = new ToolsListCount();
toolsListCount.setList(pagedList.getList());
toolsListCount.setCount(pagedList.getTotalRowCount());
return toolsListCount;

ORMLite or Query across multiple tables

I am trying to query a table based on criteria from a join table using ORMLite.
Here is how I would express the query I am trying to write in tsql:
select * from media m inner join file f on m.fileId = f.fileId
where m.isNew = 1 OR f.isNew = 1
The result should be a list of media records where either the media record or the corresponding file record has isNew = 1.
I have read through the documentation on using OR in ORMLite, but all of the examples use a single table, not joining. Likewise I have read the documentation on joins, but none of the examples include a where clause that spans both tables. Is there any way besides a raw query to do this?
I had a look at this question: https://stackoverflow.com/a/12629645/874782 and it seems to ask the same thing, but the accepted answer produces an AND query, not an OR. Here is my code that I used to test that theory:
public List<Media> getNewMedia() {
Session session = getSession();
Account account = session.getSelectedAccount();
ContentGroup contentGroup = account.getSelectedContentGroup();
List<Media> results = null;
try {
QueryBuilder<Category, Integer> categoryQueryBuilder = getHelper().getCategoryDao().queryBuilder();
categoryQueryBuilder.where().eq("group_id", contentGroup.getId());
QueryBuilder<MediaCategory, Integer> mediaCatQb = getHelper().getMediaCategoryDao().queryBuilder();
mediaCatQb = mediaCatQb.join(categoryQueryBuilder);
QueryBuilder<FileRecord, Integer> fileQueryBuilder = getHelper().getFileDao().queryBuilder();
fileQueryBuilder.where().ge("lastUpdated", contentGroup.getLastDownload());
QueryBuilder<Media, Integer> mediaQb = getHelper().getMediaDao().queryBuilder();
mediaQb.where().eq("seen", false);
// join with the media query
results = mediaQb.join(fileQueryBuilder).join(mediaCatQb).query();
} catch (SQLException e) {
Log.e(TAG, "Sql Exception", e);
}
return results;
}
For the sake of completion, this is querying for a slightly more complex example than the one I gave above, this one expressed in tsql would be
select * from Media m join FileRecord f on m.fileRecordId = f.fileRecordId
where m.seen = false OR f.lastUpdated >= lastUpdateDate
When I run it, it is actually doing an AND query, which is what I would expect based on two joins with independent where clauses.
I think the key issue is that a where clause is inherently tied to a table, because it is performed on a QueryBuilder object which comes from a Dao that is specific to that table. How can I get around this?
I think what you are looking for is joinOr search for it in the ORMLite docs.
Like join(QueryBuilder) but this combines the WHERE statements of two
query builders with a SQL "OR".

problem with HQL update

When I try to execute the following HQL query:
Query query = getSession().createQuery("update XYZ set status = 10");
query.executeUpdate();
I get this exception:
Exception in thread "main" org.hibernate.QueryException: query must begin with SELECT or FROM: update
EDIT:
I also tried following .But it doennot work either.
org.hibernate.Query query = getSession().createQuery("update XYZ t set t.status = 10");
EDIT2:
Making changes in hinbernate.cfg.xml solved my problem
Earlier i was using
setting hibernate.query.factory_class" = org.hibernate.hql.classic.ClassicQueryTranslatorFactor
Now am using following property
<property name="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</property>
Thats not an HQL query.
You want to import javax.persistence.Query which allows normal sql,
not org.hibernate.Query which works on entity objects.
If you want to use simple sql, you could also use PreparedStatement
However, if you really want to use hibernate, without taking advantage of entityobjects (totally defeating the point of using hibernate in the first place, imho) you could do it like this (reference docs):
String myUpdate = "update XYZ myAlias set myAlias.status = :newStatus";
// or String noAliasMyUpdate = "update XYZ set status = :newStatus";
int updatedEntities = getSession().createQuery(myUpdate) //or noAliasMyUpdate
.setInt( "newStatus", 10 )
.executeUpdate();
The question is thinking in SQL, when you should be thinking in objects:
XYZ xyz = new XYZ();
xyz.setStatus(10);
getSession().merge(xyz);
Try:
Query query = getSession().createQuery("update XYZ o set o.status = 10");
query.executeUpdate();
Take a look at this also.
Session sesssion = getSession(); //getter for session
For HQL :
String hql = "update Activity " +
"set startedOn = :taskStartedOn " +
"where id = :taskId";
Query query = session.createQuery(hql);
query.setDate("taskStartedOn",new Date());
query.setLong("taskId",1)
int rowCount = query.executeUpdate();
Here Activity is POJO.
Use
hibernate.query.factory_class = org.hibernate.hql.ast.ASTQueryTranslatorFactory
in hibernate.cfg.xml file to resolve exception:
org.hibernate.QueryException: query must begin with SELECT or FROM: update.....

Categories