Skip to main content

Intercepting and adjusting SQL generated by Eclipselink JPA

In some cases it might be useful to intercept and adjust the SQL generated by EclipseLink JPA. E.g. if you want to force an index in mysql you need to append force index (myindex) to the table name.

If you create a query on the entitymanager:

Query q = em.createQuery("select e from MyEntity");

you can cast it to the EclipseLink JpaQuery:

JpaQuery jq = (JpaQuery)q;

and the JpaQuery gives you access to the EclipseLink DataBaseQuery where you can prepare it before executing it:

DatabaseQuery dbQuery = q.getDatabaseQuery();
dbQuery.prepareCall(((org.eclipse.persistence.jpa.JpaEntityManager)em).getActiveSession(),new DatabaseRecord());

You can now get the sql string and add the forced index:

dbQuery.setSQLString(dbQuery.getSQLString()+" force index (myindex)");

and finally you can get the resultset using q.getResultList().

If you have parameters in the sql it's a bit more to it. Currently I've only found one option - probably not optimal since the query is translated to non-parameterized query:

dbQuery.getTranslatedSQLString(session, dbrecord);

This will give you an sql with all the parameter values inside - so you can easily modify it - but precautions should be considered regarding SQL injection.

Using this approach Eclipselink seem to not have added the LIMIT clause in the prepared statement. The LIMIT clause is added for mysql if you use setFirstResult/setMaxRows. In this case you'll have to append the LIMIT clause manually - and make sure that EclipseLink ignores firstResult/maxRows.


dbQuery.setSQLString(dbQuery.getSQLString()+" force index (myindex) LIMIT "+firstResult+","+maxRows);
dbQuery.getCall().setIgnoreFirstRowSetting(true);
dbQuery.getCall().setIgnoreMaxResultsSetting(true);

Ideally the query should have been modified using the parameterized version, so that also EclipseLink could add the LIMIT clause and bind the parameters - but this is how far I got in this round. If someone knows how to do this better - please leave a comment.

Comments

Popular posts from this blog

Angular components not reloading on route change

Spent a long time wondering why route changes caused strange effects on my component, and found out that it was because my component wasn't reloading at all. I had this assumption that when a route parameter changed (e.g. /projects/1 changed to /projects/2 ) the component for the route would be reloaded. But this is not the default behaviour of the Angular router. The default behaviour of the Angular router is to reuse the route if the configuration is the same (and not reload the component). But we can override this by providing a RouteReuseStrategy to our @NgModule: providers: [ { provide: RouteReuseStrategy, useClass: AARouteReuseStrategy } ] The full custom implementation of the RouteReuseStrategy will then be like this (and it's the shouldReuseRoute method that changes the behaviour so that the component is reloaded on route parameter change): export class AARouteReuseStrategy extends RouteReuseStrategy { shouldDetach(route: ActivatedRou...

Using Angular i18n translation strings outside templates

As of today in Angular 6 i18n is only available in the templates. So what if we want to use translated messages programatically and outside templates? I still use the component template html file to declare the message to be translated, but by obtaining the TemplateRef ViewChild in the component typescript file I can get the translated messages from typescript. <ng-template #boardInvitationEmailBody let-organization="organization" let-url="url"> <ng-container i18n>You have been invited to join the board portal for</ng-container> {{organization}}. <ng-container i18n> Please follow the link to: </ng-container> {{url}} </ng-template> So in the typescript code i can now call the createEmailBodyTranlated text method to get the translated text for use outside the template. @ViewChild('boardInvitationEmailBody') boardInvitationEmailBody: TemplateRef ; createEmailBodyTranslatedText(org...

Using GIT for offline web app syncing and storage

Offline web applications, progressive web apps (PWA) using service workers for being available offline also needs a way to sync changes with the server. Mostly we store data in JSON documents, and we could identify changes per line - which is something GIT is excellent at. So how could we make the browser a GIT client? I've been working on this for some months now, and compiled libgit2 to webassembly using emscripten - and it turns out to work very well. Some video demos: Cloning a repository: https://youtu.be/rcBluzpUWE4 Merging of file changes: https://youtu.be/xfGrMwLy_tw The project is here: https://github.com/fintechneo/angular-git-filebrowser