JPA query does not return any data - java

I have a following JPA query:
#Query(value = "select r FROM TableEntity r where r.time=?1")
TableEntity findByTime(java.sql.Timestamp time);
That query is pretty straightforward, should fetch the database row based on some time. It works like a charm with MYSQL and Oracle but won't work for MSSQL. I have debugged the query through Hibernate and JTDS driver and saw that Timestamp is successfully resolved in the Prepared statement, I can see the exact number of hours, minutes, seconds and milliseconds in query as I have in the database row. However, no data is returned back.
class TableEntity {
#Type(type = "timestamp")
private Timestamp time;
}
I am suspecting that some milliseconds rounding happens or they somehow gets messed up since query does return something once in a blue moon!
My Time Field in the database is datetime2(3)
I am using the net.sourceforge.jtds 1.3 driver.
Time is formatted like this: 2020-06-03 13:02:21.273, I am working with milliseconds
EDIT:
I tried writing plain prepared statement and here are results:
select r FROM TableEntity r where r.time=?1
preparedStatement.setTimestamp(1, timestamp); //does not work...
preparedStatement.setString(1, timestamp.toString()) //works like a charm
Any idea?

So, under the hood, Hibernate was mapping that timestamp to datetime type when it queried the DB (I concluded that using the MSSQL profiler) . Since I had datetime2 in the DB, comparing datetime with datetime2 on the DB level was not returning anything even if they were exactly the same in Milliseconds.
Solution would be to force mapping of timestamp to datetime2 so db datetime2 type gets queried with the same type

Related

Return CURRENT_TIMESTAMP value with specific timezone in Spring data JPA/Hibernate (HQL) query?

I have an Spring Boot API that uses Spring data JPA (1.5.9)/Hibernate (5.0.12) to query my PostgresQL database that is hosted on AWS as a RDS. It is set to Central Time (CST) I have some HQL (Hibernate) queries that use the CURRENT_TIMESTAMP function, but unfortunately and oddly seems to be returning UTC return values for whenever the HQL queries that use CURRENT_TIMESTAMP run.
I need a way to simply force the CURRENT_TIMESTAMP in the HQL query to be central time (CST). I was trying just querying the DB in pure SQL and something like this worked:
CURRENT_TIMESTAMP at TIME ZONE 'America/Chicago'
Unfortunately, I can't seem to get that to work in HQL, as IntelliJ/Hibernate throws a compilation error for:
<expression> GROUP, HAVING, or ORDER expected, got 'AT'
My sample HQL query I am using is:
#Query(value = "SELECT customerCoupons FROM CustomerCouponsEntity customerCoupons "
+ "WHERE customerCoupons.couponCode = :couponCode "
+ "AND customerCoupons.expiredDate >= CURRENT_TIMESTAMP "
+ "AND customerCoupons.startDate <= CURRENT TIMESTAMP "
)
List<CustomerCouponsEntity> findByCouponCode(#Param("couponCode") String couponCode);
Any help would be greatly appreciated. I have the DB set as CST in AWS, so I didn't even expect this CURRENT_TIMESTAMP to be returning a UTC value (still doesn't make sense to me, unless its somehow using the JDBC driver TimeZone or JVM? I mean, this is a Hibernate query, so its not pure SQL right?)
You should try to set the hibernate timezone in your spring boot properties file. Example:
spring.jpa.properties.hibernate.jdbc.time_zone=YOUR_TIMEZONE
Ensure that the value of YOUR_TIMEZONE matches your DB timezone.
I guess this article will help
Posting my own answer;
I tried setting the timezone in the properties/yaml per this article:
https://moelholm.com/blog/2016/11/09/spring-boot-controlling-timezones-with-hibernate
but it did not work no matter what I tried. I made sure I was on hibernate 5.2.3 or greater and it wouldn't work.
I also tried adding the "AT TIMEZONE" in my HQL query but the code wouldn't compile. I guess even though this is valid SQL it doesn't work with the Hibernate SQL queries i.e.
CURRENT_TIMESTAMP at TIME ZONE 'America/Chicago'
Anyway, the only thing that seemed to work was:
#PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}

Comparing current date (Java) to a Timestamp in a DB (sql) using Hibernate

I am trying to check if an entry to the DB has occurred today. My Query works when I run it with MySqlWorkbench, but when I use hibernate the query does not seem to work correctly I am always returned true even though the DB does have dates today.
The query is:
#Query("SELECT CASE WHEN (count(ent) < 1) then true else false end
FROM Entity ent WHERE ent.createdAt >= (?1)")
boolean checkIfEnteredToday(Date date);
The date is from the java.sql.Date library.
I solved it by changing the DataType of The entity's datetype for 'created_at' to java.sql.Date, whereas previously it was java.sqlTimestamp.

How can I query the average difference of dates in days using HQL (Hibernate)?

I need to retrieve from my PostgreSQL database, which has been mapped to Java using Hibernate, the average difference of dates (start and end, as you may say) of the records.
I wrote a native PostgreSQL query which works fine:
SELECT avg(date_part('days', age(datasaida, dataentrada))) as avg_days
FROM processo.processo
WHERE processo.codsituacao = '14'
AND processo.dataEntrada >= now() - interval '30 days';
The problem is that I can't figure out how to translate this query to HQL (Hibernate SQL) because of the avg(date_part('days', age(datasaida, dataentrada))) part.
I need the information to be shown in the front-end, which I am building with JSF Primefaces.
P.S.: dataEntrada - means startDate (kind of). dataSaida means endDate (kind of)
You could try
avg(DAY(function('age', datasaida, dataentrada)))
or
avg(DAY(datasaid - dataentrada))
DAY is standard JPA function: http://www.objectdb.com/java/jpa/query/jpql/date
And with function('age', datasaida, dataentrada) you call a database specific function from JPA
Well you can use function('function_name', param1, param2) in the HQL to call the native Postgresql functions:
SELECT avg(function('date_part', 'days', function('age', datasaida, dataentrada))) as avg_days
FROM processo.processo
WHERE processo.codsituacao = '14'
AND processo.dataEntrada >= now() - interval '30 days';
For further details you can check the Call PostgreSQL-specific SQL Functions section of the Hibernate with PostgreSQL – 6 things you need to know tutorial.

Java driver delete partition by timestamp

I am retrieving data from Cassandra and mapping it to a class using the build in object mapping API in the java driver. After I process the data I want to delete it. My clustering key is a timestamp and it is mapped to a Date object. When I try do delete a partition it does not get deleted. I suspect that it is because of the mapping to the Date object and that some data is lost there? Have you encountered a similar problem?
The Accessor:
#Query("SELECT * FROM my_table WHERE id = ? AND event_time < ?")
Result<MyObject> getAllObjectsByTime(UUID id, Date eventToTime);
The retrieval of the objects:
MappingManager manager = new MappingManager (_cassandraDatabaseManager.getSession());
CassandraAccessor cassandraAccessor = manager.createAccessor(CassandraAccessor.class);
Result<MyObject> myObjectResult = cassandraAccessor.getAllObjectsByTime(id, eventToTime);
MyObject:
#Table(keyspace = "myKeyspace", name = "my_table ")
public class MyObject
{
#PartitionKey
#Column(name = "id")
private UUID id;
#Column(name = "event_time")
private Date eventTime;
}
The delete logic:
PreparedStatement statement = session
.prepare("DELETE FROM my_table WHERE id = ? AND event_time = ?;");
BatchStatement batch = new BatchStatement();
for (MyObject myObject: myObjects)
{
batch.add(statement.bind(myObject.getStoreId(), myObject.getEventTime()));
}
session.execute(batch);
EDIT
After a lot of debugging I figured, that maybe the Date is not the problem. It appears that the delete is working, but not for all of the partitions. When I debug the Java application I get the following CQL statement:
DELETE FROM my_table WHERE id=86a2f31d-5e6e-448b-b16c-052fe92a87c9 AND event_time=1442491082128;
When it is executed trough the Cassandra Java Driver the partition is not deleted. If I execute it in the CQLSH console the partition is deleted. I have no idea what is happening. I am starting to suspect that there is a problem with the Cassandra Java Driver. Any ideas?
Edit 2
This is the table:
CREATE TABLE my_table(
id uuid,
event_time timestamp,
event_data text,
PRIMARY KEY (id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC)
I'd need to see more of your code to understand how you are issuing the delete, but perhaps you aren't specifying the timestamp to the correct precision on the delete.
Internally timestamp fields are epoch time in milliseconds. When you look at a timestamp in cqlsh, it shows the timestamp rounded down to the nearest second like this:
SELECT * from t12 where a=1 and b>'2015-09-16 12:51:49+0000';
a | b
---+--------------------------
1 | 2015-09-16 12:51:49+0000
So if you try to delete using that date string, it won't be an exact match since the real value is something like 2015-09-16 12:51:49.123+0000
If you show the timestamp as an epoch time in milliseconds, then you can delete it with that:
SELECT a, blobAsBigint(timestampAsBlob(b)) from t12;
a | system.blobasbigint(system.timestampasblob(b))
---+------------------------------------------------
1 | 1442407909964
DELETE from t12 where a=1 and b=1442407909964;
See this.
I have seen problems with batched statements being dropped or timing out. How many deletes are you trying to execute per batch? Try either lowering your batch size or removing batching all-together.
Remember, batch statements in Cassandra were designed to apply an update atomically to several different tables. They really weren't intended to be used to slam a few thousand updates into one table.
For a good description of how batch statements work, watch the video from (DataStax MVP) Chris Batey's webinar on Avoiding Cassandra Anti-Patterns. At 16:00 minutes he discusses what (exactly) happens in your cluster when it applies a batch statement.

How do I get CURRENT_DATE in MSSQL?

I am using jpa 3.o with Hibernate. I have one named query:
SELECT COUNT(wt.id) FROM WPSTransaction wt WHERE wt.createdDate>= CURRENT_DATE
WPSTransaction is my entity class and createdDate is one of the columns in my class.
It's working fine in the Mysql Database. However, I'm moving to SQL Server 2012 and SQL server doesn't seem to compile the CURRENT_DATE value. I've tried GETNOW() and NOW() methods as well as current_date() method and CURRENT_TIMESTAMP without any luck.
MS SQL Server fails to conform to the standard here - it does not provide a current_date keyword.
You must instead use the SQL-server specific GETDATE() function, as the document linked shows.
Because current_date is a keyword in the spec, you can't just create a user-defined current_date() function in MS SQL and expect it to work the same. So unfortunately you're stuck with database-specific code here.
The function to return the current date in MS SQL is GETDATE(), so your query should read
SELECT COUNT(wt.id) FROM WPSTransaction wt WHERE wt.createdDate >= GETDATE()
How about:
Query q = entityManager.createQuery("SELECT COUNT(wt.id) FROM WPSTransaction wt WHERE wt.createdDate>= :d");
q.setParam("d", new Date());
No database specific code needed.

Categories