I've a query which needs to be constructed as String first.
StringBuilder query = new StringBuilder();
query.append(....);
query.append(....);
I want to pass this query as a native query, like:
myTableRepository.insertData(query.toString());
So in MyTableRepository I can use it like we generally use native queries using #Query annotation.
Is it possible?
P.S. - I'm not using createNative(), due to some legacy issue, I don't want to use EntityManager.
I don't think it is possible , it will exposes your code to jpql injection attack, and from perspective of DB optimizer it cause bad performance cause it have to create query each time. You can use Criteria query to build safe dynamic query.
Related
I want to create a parametrized query to receive something from the database. This query is big, that big that it is not really possible to put it in a #Query annotation in a CrudRepository and also it should be very flexible so that depending on parameters it may add a join or a with segment to the query.
The way I saw this situation being handled was building the query in a String variable and then passing that string to a JdbcTemplate or being executed in another ways. Something like that:
String sql = getWith(params) + getJoin(params) + getWhere(params);
These methods can get very big and ugly.
Is there a way I can achieve my goal more elegantly?
How can i use jpa for query over an object (not an entity)?
For example this simple code:
String [] theList = {a,b,c,d}.
Query q = new Query("Select tl from theList tl")
Reason behind: the queries are dynamically created and executed, but the objects in the from clause of the jpql query aren't necessarily mapped tables. In some cases there are just an Object, So the actual behavior needed is modify the query during execution of the program to meet the criteria, but i don't know how to modify the query.
Edit: I Don't use native queries because of portability of code. It will be the last option.
What you're looking for is called LINQ, and unfortunately (?) it is available only in C#.
However, you can partially emulate it with Stream(s).
A Stream offers basically all the operators you need
.filter() where
.max() max
.sorted() orderby
.limit() limit
.skip() offset
.collect(groupingBy()) group by
And so on. Just give a look at the Javadoc!
I think 'JdbcTemplate' would suffice your requirement.
JdbcTemplate gives you the flexibility to run native queries and map them to a Java class.
However, you'll have to explicitly map your Java class with the column names in the database.
I have solved using joSQL. Is a powerfull opensource tool that allows you to query over java objects using "sql". It is not jpa but satisfied my needs.
Another tool i have seen that do that is called querydsl.
I have a existing code where the application generates different sql depend of lot of conditions and execute them via hibernate sessions createSQLQuery(). In here the parameters are concat to the sql string which reside in the java class as normal string replacement. The problem here is now i need to prevent sql injections. So for that i have to use getNamedQuery() and bind the parameters so hibernate will take care of special characters. But the problem is moving the string sql's to xml file is a overhead because conditionally generating sql's. So i decide to manually do the special character validation and append it to the string query and execute as it is now.
So then i check the source for PrepareStatement i found, it just throw a exception
byte[] arrayOfByte1 = new byte[0];
try
{
arrayOfByte1 = CharsToBytes(this.OdbcApi.charSet, arrayOfChar);
}
catch (UnsupportedEncodingException localUnsupportedEncodingException) {
}
How can i do same kind of encoding in the java class as above for the parameters before concat them with the string query for eliminate sql injections? Or is there any way i can still keep the string sql as it is an append parameters and use hibernate to execute the query?
As far as I can tell, you want to create SQL queries on the fly because the combination of conditions (from the UI, I guess) can be very complicated. That's fine. All you need to control are the parameters that the user supplies. And for that, you can, and should, still use Hibernate's createSqlQuery(). That function understands either ? for positional parameters (numbered from beginning of query string), or :param_name syntax and then you supply named parameters. You don't need to move anything into an xml file.
Section 16.1.7 has examples.
If you need to assemble custom SQL into a query, I've found writing my own criteria classes that includes the custom SQL works well.
You just need to implement the Criterion interface.
https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/criterion/Criterion.html
(See also the Hibernate implementation of 'not null': http://www.grepcode.com/file/repo1.maven.org/maven2/org.hibernate/hibernate/3.2.4.sp1/org/hibernate/criterion/NotNullExpression.java?av=f .)
Then you can simply build up each custom query using the normal hibernate criteria API.
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html#querycriteria-creating
Sanitising SQL values properly is painful - try really hard to avoid it! ;-)
What advantages does get have over createQuery?
I can see there might be a slight performance improvement in not having to parse the HQL, but is there any other major advantage to using get over createQuery?
First, it's much quicker to type, is much more readable, and expresses the intent clearly: get an entity by its ID. And it's basically impossible to make an error, whereas you could have a typo in your HQL query.
Regarding performance, the main advantage is that it executes a select statement only if the entity is not in the session cache yet. An HQL query will be executed every time. And if you have a second-level cache, get() will avoid executing a query completely if the entity is already in the second-level cache.
get() uses directly session to retrieve objects.
get() only useful when you want to load an object i.e. SQL SELECT.
Like save() and persist() result in an SQL INSERT, delete() in an SQL DELETE and update() or merge() in an SQL UPDATE.
limited control and we need specify an entity that we need to extract.
createQuery() uses HQL
Using HQL we can write all CRUD queries.
give more control we can specify HQL(SQL like) clauses.
HQL is the own query language of hibernate and it is used to perform bulk operations on hibernate programs
An object oriented form of SQL is called HQL.
Here we are going to replace table column names with POJO class variable names and table names with POJO class names in order to get HQL commands
Sometimes it is very hard to write with other alternatives. Using HQL we can implement faster.
I would like to know how safe is EJB3 to prevent SQL Injection.I've read that using prepared statements is quite safe, but for instance with a function like this
#Override
public Collection<Project> searchProjectsPerProfessorLastname(String lastname) {
Query q = manager.createQuery("SELECT DISTINCT OBJECT(p) FROM Project p JOIN p.professors prof WHERE lower(prof.lastName) = ?1");
q.setParameter(1, lastname.toLowerCase());
#SuppressWarnings("unchecked")
Collection<Project> c = q.getResultList();
if(c.size()==0)
return null;
return c;
}
it is possible to perform SQL Injection?
No.
Simply put, as long as you're not building the SQL dynamically (and binding is not building SQL), there's no risk of SQL injection. Barring a buggy SQL driver.
Binding is the technique of assigning parameters to SQL statements via the driver rather than through simply building up SQL text yourself.
Different drivers do different things, but the reason that SQL injection happens is that people creating the SQL text do not take the proper precautions to prevent SQL injection (notably escaping special characters alike quotes and such).
Ideally, the driver will take care to build the SQL properly. But if the driver is buggy in some way, there's still some risk. I, personally, have not encountered a driver had a bug that affected this. So, while it's possible, it's really, really remote.
Finally, for you example, you're not even using SQL, you're using EQL, which is the JPA query language. This has to be translated yet again from EQL to SQL, which gives more opportunity for the intervening software (JPA and the JDBC driver) opportunity to prevent a SQL injection from happening.
All the parametized query forms of JPA calls are considered safe against SQL injection. You can however, create a query string with concatenation, which would be unsafe.