How can I build a query in ORMLite so that I can use the orderBy function (using either the one with the raw string or the parametrized one) referencing an attribute of a different entity than the one of the dao I'm building the query from? My query is built like that:
// Inner query for performances
QueryBuilder<Performance, String> performancesQB = performanceDao.queryBuilder();
performancesQB.selectColumns("performance_id");
SelectArg performanceSelectArg = new SelectArg();
performancesQB.where().lt("date", performanceSelectArg);
// Outer query for Order objects, where the id matches in the performance_id
// from the inner query
QueryBuilder<Order, String> ordersQB = orderDao.queryBuilder();
ordersQB.where().isNull("user_id").and().in("performance_id", performancesQB);
ordersQB.orderByRaw("performances.date DESC");
pastOrdersQuery = ordersQB.prepare();
And the exception I'm getting whenever I try to execute this query is:
android.database.sqlite.SQLiteException: no such column: performances.date:,
while compiling: SELECT * FROM `orders` WHERE
(`user_id` IS NULL AND `performance_id` IN
(SELECT `performance_id` FROM `performances` WHERE `date` < ? ) )
ORDER BY performances.date DESC
The only solution I see here is writing a raw query myself using a JOIN instead of a nested select. May this be a good solution?
ORMLite now supports simple JOIN queries. Here the docs on the subject:
http://ormlite.com/docs/join-queries
So your query would now look something like:
QueryBuilder<Performance, String> performancesQB = performanceDao.queryBuilder();
SelectArg performanceSelectArg = new SelectArg();
performancesQB.where().lt("date", performanceSelectArg);
performancesQB.orderBy("date", false);
// query for Order objects, where the id matches
QueryBuilder<Order, String> ordersQB = orderDao.queryBuilder();
ordersQB.join(performancesQB).where().isNull("user_id");
pastOrdersQuery = ordersQB.prepare();
Related
JPA repository throwing Error for custom query method:
org.h2.jdbc.JdbcSQLException: Table "NBMRBANKDTLSENTITY" not found; SQL statement:
select NBMRBankDtlsEntity from NBMRBankDtlsEntity where NBMRBankDtlsEntity.ipphId = ? [42102-191]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
Class :
#Repository
public interface NBMRBankDtlsRepository extends JpaRepository<NBMRBankDtlsEntity, Long> {
#Query(value ="select n from NBMRBankDtlsEntity n where n.ipphId = :ipphId",nativeQuery = true)
Optional<NBMRBankDtlsEntity> findByIPPHId(#Param("ipphId") Long ipphId);
}
The error message tells you: Table "NBMRBANKDTLSENTITY" not found. Therefore it probably doesn't exist. To fix this you'll have to create the table, manually through a script or through hibernates schema creation feature.
I am already creating a table also inserting the record, After that only i am calling this custom query method.
I have found the issue as i am using nativeQuery = true so it is expecting normal sql query to query DB directly not the java query which is creating issue. Now after changing below it works fine ,
#Query(value = "SELECT * from NB_MR_BANK_DTLS WHERE IPPH_ID = :ipphId",nativeQuery = true)
For java query we can use directly as it internally converts to SQL while querying the DB,
#Query(value = "select p from NBMRBankDtlsEntity p WHERE p.ipphId = :ipphId")
I have written a custom predicate that I make use of in a JpaSpecificationExecutor query. The generated SQL for this query does not make use of a parameter, and therefore the query cache has 2 entries (as the queries differ by 1 character!). Is the use of the aggregate function what is causing the difference I am seeing? (outlined below).
My application is using sqlserver 2012 for its database and I have monitored the queries via sqlserver management studio. The output of which I have observed making use of parameters for billingType and recordedDate but not recordedValue.
Below is the predicate code I have used:
Subquery<Entity> subQuery = query.subquery(Entity.class);
Root<Entity> subQueryRoot = subQuery.from(Entity.class);
subQuery.select(subQueryRoot.get("userId"));
Optional<Predicate> teamEquals = // Call to helper
Predicate isMinutes = builder.equal(subQueryRoot.get("billingType"), BillingType.MINUTES);
Predicate minutesDate = builder.greaterThan(subQueryRoot.get("recordedDate"), LocalDate.now().minus(Period.parse(params.getHoursPeriod())));
Predicate minutesThreshold = builder.greaterThan( subQueryRoot.get("recordedValue"), params.getHours() * 60 );
Predicate minutesRestriction = builder.and(isMinutes, minutesDate, minutesThreshold);
Predicate isDocuments = builder.equal(subQueryRoot.get("billingType"), BillingType.DOCUMENTS);
Predicate documentsDate = builder.greaterThan(subQueryRoot.get("recordedDate"), LocalDate.now().minus(Period.parse(params.getDocumentsPeriod())));
Predicate documentsThreshold = builder.greaterThan( subQueryRoot.get("recordedValue"), params.getDocuments() );
Predicate documentsRestriction = builder.and(isDocuments, documentsDate, documentsThreshold);
subQuery.where( builder.and(teamEquals.get(), builder.or( minutesRestriction, documentsRestriction ) ) );
return Optional.of(subQuery);
This results in 2 generated queries differing by 1 character.
E.g. (IN HQL)
SELECT * FROM User where id IN (SELECT userId FROM Entity WHERE billingType = #p1 AND recordedDate > #p2 AND recordedValue > 0)
vs.
SELECT * FROM User where id IN (SELECT userId FROM Entity WHERE billingType = #p1 AND recordedDate > #p2 AND recordedValue > 40)
This sounds like it is the following Hibernate bug https://hibernate.atlassian.net/browse/HHH-9576
Also there appears to be a workaround documented at Why Hibernate inlines Integer parameter list passed to JPA Criteria Query?
I tried to run native sql query with resulttransformer (AliasToBeanResultTransformer), it gives error like below.
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: com.ozpas.ozentegre.entity.EntDevirlog cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78)
By the way, my native sql query does not include all fields in the entity ( EntDevirlog ), there are only some fields in that entity. shall the query include all fields in the entity ?
as i understood, hibernate transforms result into a map object instead EntDevirlog entity. It uses PropertyAccessMapImpl. how can i solve this problem to get the result as a list ( arraylist ) ? thanks.
Session session = HibernateUtilMikro.getSessionFactory().openSession();
List<EntDevirlog> results = new ArrayList<EntDevirlog>();
Transaction tx = null;
String sql = "mynativequery";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("tarih", tarih);
query.setParameter("srmkodu", srmkodu);
query.setParameter("s1", EnumPanoislemtipleri.islem1.getValue());
query.setParameter("s2", EnumPanoislemtipleri.islem2.getValue());
query.setResultTransformer(new AliasToBeanResultTransformer(EntDevirlog.class));
results = query.list();
tx.commit();
Just use the quotes for the aliases
"select firstName as \"firstName\",
lastName as \"lastName\" from Employee"
Read for a more deeply explanation here:
mapping Hibernate query results to custom class?
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;
When I run the method: dao.query("SELECT p FROM Profile p WHERE p.group = :id ORDER BY p.datestamp :key", map); I get the following error:
org.hibernate.hql.ast.QuerySyntaxException:
unexpected token: : near line 1,
column 93 [SELECT p FROM Profile p
WHERE p.group = :id ORDER BY
p.datestamp :key]
Following is the query method implemenation; anyone see what is wrong?
public List<?> query(String criteria, HashMap<String, ?> args) {
Query sqlQuery = this.em.createQuery(criteria);
Set<String> keys = args.keySet();
Iterator<String> iter = keys.iterator();
while (iter.hasNext()) {
String key = iter.next();
sqlQuery.setParameter(key, args.get(key));
}
return sqlQuery.getResultList();
}
You cannot use parameters to specify sorting direction, because parameter cannot be used in arbitrary places of the query. From JPA spec:
Input parameters can only be used in the WHERE clause or HAVING clause of a query.
So, in JPA 1.0 you have to build query string with appropriate ORDER clause manually.
In JPA 2.0 you can use Criteria API to construct dynamic queries.
I think you need a comma after ORDER BY p.datestamp and before :key