JPQL comparing Entities - java

I have a database which stores (among others) Presentations, which is mapped using JPA. These presentations have a starting time, and an endtime.
I'd like know whether there's an overlap before adding a new presentation. I am currently doing this with a query that selects all presentations with the same room and same date.
I'd like to add the time to this. My times are made using a custom java.sql.Time subclass (I need it for a custom constructor). I obviously don't want to map those in the database. Now I'd like to check whether a certain time is before or after another.
I'm currently using the query SELECT p FROM Presentatie p WHERE p.lokaal.code = :lokaal AND p.dag = :dag AND ( p.begin <= :einde OR p.einde >= :begin) but that is flawed because it cannot compare Time classes (my guess that it evaluates to NULL, which would explain the zero-length resultset)
I don't know how to do this. I tried adding an int time to the Time class, but I can't reach it as it's not mapped using JPA.
I'd also like to know how it checks p.dag = :dag, is it equivalent to dag == dag2or dag.equals(dag2)? And how does it compare the time? time > time2 (but this doesn't compile in Java, so I'm guessing it goes to time.compareTo(time2)>0?

Related

datanucleus-mongodb performance issues on 1-1 Relations

Again, I'm creating this thread to see if someone has the same issues or if someone knows how to improve performance.
Let me explain first the scenario:
I have a JDO entity named for example Product. In that product I have a field of another entity, a simple one (Example Type: long id, String name, String value) and 1 date.
I created 10000 objects of the product but when i try to query the Product with the dates the performance is good but if I add the type.id == 12 then the performance drops from 100ms to 30 secs... if I instead of having a Type object put a long typeId on the Product, then the same query is also fast... What I'm worried is with scalability, should I flatten the structures and work with ids that are not really connected but needs additional application retrieval or is there a way to improve performance on the query on a Product.Type?
Thank you very much in advance.
I've already tried to define fetchGroups, but they don't really work...
What I wanted to do actually is doing a sort of mapping via an ID on the Product, but I couldn't do it with the embedded annotation...
so, let me explain a little better: I have a class named Reading with (one Date timeStamp and a Product p). this is doing a query. If the filter is something like this:
String filter = "timeStamp > fromDate && timeStamp < toDate";
the query executes in 100ms if I do this
String filter = "timeStamp > fromDate && timeStamp < toDate && prod.id == '941'"
for example, it takes 30secs... I've seen the logs, and without the query for the product he only reads from cache, if I add the clause of the Product he seems to fetch all the objects and starts comparing values I imagine...I don't really know what to do, maybe I should disconnect all these classes and start using like a String productID on the Reading class and then everything starts to be fast again... but in reality, the connection is not there, it would be implemented in an application layer... Thanks again... Any advise?
The query generated is something like this:
SELECT FROM core.jdo.model.Readings WHERE timeStamp > fromDate && timeStamp < toDate && EAN.EAN == '002' PARAMETERS java.util.Date fromDate, java.util.Date toDate import java.util.Date

Using operator 'or' in Cassandra IndexExpression

I have an Java application with Cassandra db. I'm using Cassandra Pelops. I have a columnFamily cf1, and a lot of columns there. For some of them I created secondary index, so I can use them for search. For search purpose, I created a list of IndexExpression (expressions), for example:
final IndexExpression propertyIdExpression = new IndexExpression(
ByteBuffer.wrap(Bytes.fromUTF8(CassandraIntegrationDAOHelper.COL_PROPERTY_ID).toByteArray()),
IndexOperator.EQ,
ByteBuffer.wrap(Bytes.fromInt(entity.getProperty().getId()).toByteArray())
);
expressions.add(propertyIdExpression);
Now I need to include some additional check. I have columns dateFrom and dateTo. Requests is to return all rows where this two dates are in some interval. They don't have to be completely in the interval, important is to start or end in this interval. So, I need to somehow implement something like this:
if( (dateTo is greaterThan intervalStart) or (dateFrom is lowerThan intervalEnd) )
by using IndexExpression. Any suggestions? I hope I was clear! Thanks in advance!
Cassandra does not support disjunction ("or") in secondary index queries at this time, only conjunction ("and"). In most cases, it's sufficient to make two separate queries with each half of the disjunction and combine the results.
However, if you're dealing with time ranges, that's something you should be using column names for, not secondary indexes. I suggest checking out some of the documentation on time series data and thinking about how to restructure your data to support efficient queries based on time ranges.

Hibernate getting position of a row in a result set

I need to get an equivalent to this SQL that can be run using Hibernate. It doesn't work as is due to special characters like #.
SELECT place from (select #curRow := #curRow + 1 AS place, time, id FROM `testing`.`competitor` JOIN (SELECT #curRow := 0) r order by time) competitorList where competitorList.id=4;
My application is managing results of running competitions. The above query is selecting for a specific competitor, it's place based on his/her overall time.
For simplicity I'll only list the COMPETITOR table structure (only the relevant fields). My actual query involves a few joins, but they are not relevant for the question:
CREATE TABLE competitor {
id INT,
name VARCHAR,
time INT
}
Note that competitors are not already ordered by time, thus, the ID cannot be used as rank. As well, it is possible to have two competitors with the same overall time.
Any idea how I could make this work with Hibernate?
Hard to tell without a schema, but you may be able to use something like
SELECT COUNT(*) FROM testing ts
WHERE ts.score < $obj.score
where I am using the $ to stand for whatever Hibernate notation you need to refer to the live object.
I couldn't find any way to do this, so I had to change the way I'm calculating the position. I'm now taking the top results and am creating the ladder in Java, rather than in the SQL query.

Java Persistence Criterias; Cast Expression<Timestamp> to Expression<Long>?

I am using the CriteriaBuilder and CriteriaQuery to build my query to the database, but I have encountered an issue that I do not know how to solve, since I am very new to this whole ordeal called JPA.
In Java, I have a property called timestamp for a class called Report, and it is set to the same corresponding #TemporalType.
I also have a class called Affiliate which has a list of Report objects.
In my query, I want to fetch all the Affiliate objects that do not have a Report in the last Affiliate.maxSilenceMinutes.
My questions:
Are there any ways in standardized JPA to modify dates? Like a CriteriaBuilder.subtractMilliseconds(Expression<Timestamp>, Long) of sorts?
If not, is there a way to cast Expression<Timestamp> to Expression<Long> so that I can subtract on a currentTimestamp literal to get the minimum value for a CriteriaBuilder.lessThanOrEqualTo(greatestReportTimestampMs, minimumAllowedMs)?
I know this might feel like a confusing question, but the main part is simply: Is it possible to go Expression<Timestamp> to Expression<Long>? It throws an exception for me if I try to use the .as(Long.class) method, but which should be the default underlying data type in most DBs anyway?
Hope you guys can help, since I feel kind of stuck :)
If you know the value you want to subtract at the time of querying,
you can subtract beforehand:
Calendar c = new Calendar();
c.setTime(timestamp.getTimestamp());
c.add(DAY, - someNumberOfDays); //or whatever unit you want
Date d = c.getTime();
If not, you probably need to call a database function to do the subtraction, via
CriteriaBuilder.function()
CriteriaBuilder.lessThanOrEqual() works on Comparables. Timestamps are comparable. So you could construct a Timestamp via new Timestamp(long ms)
and compare it with the other expression.
I hope this helps.
This is not built into Hibernate, so you will need a custom function of some kind.
The JDBC standard includes a function escape {fn TIMESTAMPADD( SQL_TSI_SECOND, secs, timestamp)} which should be translated into the correct SQL for the target database, but not all JDBC implementations provide it. There is therefore a chance you can add a custom StandardJDBCEscapeFunction to Hibernate's Dialect to get the result you need.
If you don't have that available, you'll have to find out what the correct database specific implementation is and there is a lot of variability here. For example:
Oracle: (timestamp + secs/86400)
SQLServer: DATEADD(ss,secs,timestamp)
DB2: (timestamp + secs SECONDS)
MySQL: DATE_ADD(timestamp, INTERVAL secs SECONDS)
Once you know it, you can use the correct expression as an SQL criteria.
The fact that date-time manipulation is not standardised in the Dialect and not fully implemented in many JDBCs means that what you are trying to do will be very difficult to write in a database neutral way.

Filter CayenneDataObject getXXXArray() entries with parameters?

My DB model is as following:
A.id (1 : n) B.ad_id
So in cayenne for object A a I can do a.getBArray() which returns me all the entries from B from this given A entry. Yet I would like to filter on this list, based on the property active = 1.
Obviously I can use Expression.fromString("active = 1") with SelectQuery, but for this approach I can't find how I associate the A instance under which I want to run this query on.
A different approach is to retrieve all entries from a.getBArray() and filter in code searching only those that have active == true, this approach is IMHO inefficient.
Recommendations are mostly appreciated.
Thank you,
Maxim.
-- EDIT:
My current solution to is (object names have been replaced with a & b respectively):
long aId = DataObjectUtils.longPKForObject(db_a_instance);
String bSQL = "select * from b where active = 1 and a_id = " + aId;
SQLTemplate bQuery = new SQLTemplate(B.class, bSQL);
List<B> dbBs = context.performQuery(bQuery);
and I'm asking if there is a better, more elegent solution?
Thanks.
I've asked similar question on Cayenne's friendly mailing list. You can see here.
It seemed to be the preferred approach is to go via relationship and filter in Java unless the relationship returns very large data. The benefit of doing so that the full list will be in memory and next time when you use relationship, you don't need to make a trip to DB.
The answer is quoted here
Both require a trip to the DB.
(the traversing in relationship approach) requires a trip one time to the DB to fault the groups from the DB, but then it'll be in memory.
(the query with filter approach) requires a trip to the DB every time, so that could be slower in the long run even though it returns fewer matches.
If this is something that only happens once and you are REALLY
concerned about performance (and possibly have a LOT of groups), I'd
go with #2, otherwise #1. You can optimize #1 a bit, too, so you
don't have to iterate each time to check.
via: Michael Gentry

Categories