SQL\HQL queries repository - java

While working on some java projects i've saw some sort of SQL repository.
The idea was to place all queries in one(or few) xml files and retrieve them when needed by name. Something like this:
String sql = getSQLRepository().getSQL("SELECT_ALL_ROWS", params)
String sql2 = getSQLRepository().getSQL("SELECT_ROWS_WITH_COND", params)
In my current Grails project i have a lot of HQL queries in dozens of classes and it's hard to track them all. It seems that HQL repository would be very nice solution.
So could anyone tell if some sort of SQL\HQL repository implementation allready present or there are better solutions present ?

Have a look at Mapping Queries in Hibernate reference.

After we started use the http://source.mysema.com/display/querydsl there is no need to think about text queries and how to manage them.

I'd recommend you to use the good old properties files. You can put them into your classpath and then use as following:
Properties sql = new Properties();
properties.load(getClass().getResourceAsStream("sql.properties"));
////////
String query = sql.get("SELECT_ALL_ROWS");

I'm sorry, and it doesn't relate to Hibernate, but when I worked with iBatis, - there are the situation as you are writing about exactly. A few xml (partially generated itself) files, containing SQL queries, which was easily to use in DAO

Related

Spring Boot: keywords supported for JPA

I wanted to perform the Spring JPA repository where wanted to apply the and operation among 2 columns where one column cloud have multiple values in it.
SQL query for the same:
select * from table_name where col1='col1_val' and col2 IN
('col2_val_a','col2_val_b','col2_val_c');
I know that for and operation I can extend the JpaRepository and create the method with like this for:
List<MyPoJoObject> findByCol1AndCol2(String col1_val,String col2_val);
and for IN operation we can use : findByCol2In(Collection<String> col2_val)
But i did not know how i can club both the mentioned JPA default method into one, as per my sql statement mentioned before.
You can use the following method named:
List<MyPoJoObject> findByCol1AndCol2In(String col1_val, Collection<String> col2_val);
On this link repository-query-keywords you can find repository query keywords that you can use and combine them as well.
You can certainly combined both into one method.
List<MyPoJoObject> findByCol1AndCol2In(String col1_val,String[] col2_val);
Try this. I am not sure if it will accept Collection<String>. I will try that and update the answer.
HTH.
If you want to perform this logic for more than two columns then your method name becomes verbose.
Instead of stuck with Spring naming why can't you write your own JPA query.
Example:
#Query("select pojo from MyPoJoObject as pojo where pojo.col1 = :col1_val and pojo.col2 in :col2_val")
List<MyPoJoObject> findByColumns(String col1_val, List<String> col2_val);

Embedded database and multiple catalogs

I want to create integration tests for my repositories. The production database is Sybase and it consists of multiple catalogs in which there are multiple schemas.
In my code I use multiple queries I am selecting data across different catalogs: ex:
select *
from catalog_a.schema_a.table_1 aa1, catalog_b.schema_a.table_2 ba2
where aa1.c1 = ba2.c2
So for the tests I would like to create embedded database, like H2, HSQLDB or something different. I was trying to find something that would allow me to simulate prod db with multiple catalogs, but I couldn't make it work. Please advice and suggest the solution.
I am writing app in java/spring. Additional trick here is that my app is creating only one DataSource to database.
HSQLDB supports only a single catalog and the name is checked when the catalog is specified in a query. You can change the catalog name from the default PUBLIC to something else. For example:
ALTER CATALOG public RENAME TO to catalog_a
But using two different catalog names is not supported.
If your schema or table names in the two catalogs are different, you could modify the source code of HSQLDB and disable the catalog name check for your tests in the method org.hsqldb.ParserDQL.checkValidCatalogName(String name)
I managed to achieve this in H2 via IGNORE_CATALOGS property and version 1.4.200.
However, the url example from their docs did not seem to work for me, so I added a statement in my schema.xml:
SET IGNORE_CATALOGS = true;

How to select schema at runtime using Hibernate?

I already have an existing code base, where schema(like db_1, db_2..) are created at run time.
We are currently using JdbcTemplate, using that its quite easy to append schema in the native SQL queries some thing like :-
sql = " Select * from "+schema+".user";
jdbcTemplate.query(sql, new UserMapper());
Now I want to know is how to provide schema to hibernate at runtime like I did with the jdbcTemplate?
What connection url should I provide in hibernate.cfg.xml so that it doesn't connects to a single schema rather whole database?
Any suggestions will be helpfull.
P.S: I am new to hibernate (So I might have missed something stupid)
I know of two options:
Use native SQL query binding results to JPA entities. Details here.
Use Hibernate multi-tenancy. Details here and here.
Although I haven't tried either.

Query with dynamic schema without using string concatenation

I have a system that uses a Oracle database, with a schema that is different from the application user. The schema name itself is not known in advance, so we can't just hardcode it. It's a system property.
Most of the data access is through Hibernate, which can specify the default schema on connection so this is not a problem in those cases.
However, there are a few places where plain SQL queries are used (using spring jdbcTemplate). So right now we have something that boils down to:
Map<String,Object> result = jdbcTemplate.queryForMap("SELECT A, B, C FROM "+schema+".TABLE WHERE blablablah");
And this, of course, is an open SQL injection vulnerability. We're planning security audits and this will be flagged for sure.
So the question is: How do I specify the schema on the query, be it with jdbcTemplate, another Sprint data access utility, or even plain jdbc?
Thank you,
JGN
You can use Connection.setSchema to specify the schema for a JDBC connection. This should be done before you create the Statement to execute a SQL command.

Using native queries but maintaining database independence

With Spring JPA is there an easy way to use native queries but maintaining database independence, for example by using the query which fits best?
At the moment I do this by checking the currently set Dialect from the Environment and call the proper method of my Repository:
public Foo fetchFoo() {
if (POSTGRES_DIALECT.equals(env.getRequiredProperty("hibernate.dialect"))) {
return repo.postgresOptimizedGetFoo();
}
return repo.getFoo();
}
This works but I have the feeling that there is a better way or that I am missing something. Especially because (Spring) JPA allows it to use native queries quite easily but that breaks one of its big advantages: database independence.
As per my understanding, this can be achieved simply by using #Transactional(readOnly=false) and then instead of calling session.createQuery, one can use session.createSQLQuery, as provided in this example.
Your sql can be any of your native query.
Hope this works for you. :)
#Override
#Transactional(readOnly = false)
public Long getSeqVal() {
Session session = entityManager.unwrap(Session.class);
String sql = "SELECT nextval('seqName')";
Query query = session.createSQLQuery(sql);
BigInteger big = (BigInteger) query.list().get(0);
return big.longValue();
}
This is just an idea: I do not know whether it works or not:
My idea would be having subinterfaces, one normal Spring-Data-JPA-interface with all methods for one entiy (without native query hints). Than I would crate a subinterface for every database, that "override" the database specific native statements. (This intrface would be empty if there are no DB specific statements). Then I would try configure Spring-JPA with some profiles to load the right specific interface (for example by a class-name or package-name-pattern)
This seems like a way to complicated way to get queries to work.
If you really want to use optimized queries make it at least transparant for your code. I suggest using named queries and create an orm.xml per database (much like Spring Boot uses to load the schema.xml for a different database).
In your code you can simply do
public interface YourRepository extends JpaRepository<YourEntity, Long> {
List<YourEntity> yourQueryMethod();
}
This will look for a named query with the name YourEntity.yourQueryMethod. Now in your orm.xml add the named query (the default one and in another one the optimized one).
Then you need to configure your LocalContainerEntityManagerFactory to load the specific one needed. Assuming you have a property defining which database you use, lets name it database.type you could do something like the following
<bean class="LocalContainerEntityManagerFactoryBean">
<property name="mappingResources" value="classpath:META-INF/orm-${database.type}.xml" />
... other config ...
</bean>
This way you can keep your code clean of the if/then/else construct and apply where needed. Cleans your code nicely imho.

Categories

Resources