I'm looking for an utility to run a JPA query and display the query along with its results in console. Just like running a select statement in native sql client:
ij> select * from standalonejpa.Emp_PHONE;
EMPLOYEE_ID|PHONE_NUM |PHONENUMBE&
--------------------------------------------
1 |12938302 |0
I would like to write a method that would accept one parameter - table name - and produce above statement to console by running EntityManager's createQuery() and getResultList(). Do you know such utility or I have to carefully craft it myself?
Not sure about a utility, but you can enable logging to show the resulting SQL.
As for crafting one, I would create a listener that interfaces with EclipseLink's logger to capture the log output then display it on the screen.
You can send JPA queries directly through the persistence layer, the only thing you can't do (or can't do easily) at runtime is adding new classes as the JPA enabled classes have to be known at startup. Though there should be an implementation specific way to register new JPA classes at runtime.
I ended up with the solution that uses JDBC query and pretty print the results with Derbytools utility class. I'm selecting all tables from the JPA project like that:
Connection conn = em.unwrap(Connection.class);
Statement st = conn.createStatement();
for(EntityType<?> et : emf.getMetamodel().getEntities()) {
String query = "SELECT * FROM " + et.getName();
System.out.println("> " + query);
st.execute(query);
JDBCDisplayUtil.DisplayResults(System.out, st, conn);
}
As a result I have pretty formatted results like:
> SELECT * FROM Employee
ID
-----------
1
51
Here comes the information to keep completeness of this post:
I used EclipseLink java.sql.Connection unwrapping and added to my pom.xml dependency to Derbytools:
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbytools</artifactId>
<version>10.10.2.0</version>
</dependency>
Actually you can use pretty-printing from Derbytools with any database, not only Apache Derby.
The whole hassle I make was to create a "testing" project for JPA mappings, that will be displaying generated tables along with data in there. The whole project is called "jpa-testing" and it is available from my github.
Related
Does Cassandra DataStax's #Select annotation use PreparedStatements in the generated queries? Is it effective like if I use a PreparedStatement and execute it manually?
Yes, mappers also prepare the statements. If you observe the logs generated out of the mappers, you could see it prepare the statements for us. For e.g. when you configure logging you'll notice things like below when the mapper code is constructed,
DEBUG ProductDaoImpl__MapperGenerated - [s0] Initializing new instance for keyspace = ks_0 and table = null
DEBUG ProductHelper__MapperGenerated - [s0] Entity Product will be mapped to ks_0.product
DEBUG ProductDaoImpl__MapperGenerated - [s0] Preparing query
`SELECT id,description,dimensions FROM ks_0.product WHERE id=:id`
for method findById(java.util.UUID)
Optional / Bonus:
As recommended in the DataStax Java Driver documentation here, you could & should definitely leverage PreparedStatements while working with QueryBuilder favoring bound statements for queries that are used often. You can still use the query builder and prepare the result:
// During application initialization:
Select selectUser = selectFrom("user").all().whereColumn("id").isEqualTo(bindMarker());
// SELECT * FROM user WHERE id=?
PreparedStatement preparedSelectUser = session.prepare(selectUser.build());
// At runtime:
session.execute(preparedSelectUser.bind(userId));
I want to integrate jOOQ in a project which uses native SQL and org.springframework.jdbc.core.JdbcTemplate. The database schema changes often and developers have to search the code for a column that has been removed and update the queries. Hibernate or another ORM solution isn't an option as queries are sometimes very large and developers get them and just have to insert into the application code. This is very error-prune. So I thought to integrate jOOQ but gradually.
Can jOOQ throw compile time errors if a native SQL cannot be executed?
I've tried the following:
// Existing code
JdbcTemplate jdbcTemplate = ...
String sql = "select ...";
// Check code
try {
DSLContext dslContext = DSL.using(jdbcTemplate.getDataSource().getConnection());
Query query = dslContext.parser().parseQuery(sql + " order by NON_EXISTING_COLUMN");
} catch (SQLException e) {
...
}
// Existing code
return jdbcTemplate.query(sql, ...)
But it compiles well although NON_EXISTING_COLUMN doesn't really exist. Maybe I know the jOOQ API not very well yet. But I thought that it should be capable of doing it. The table classes are generated, so it can check whether the query which is build from a native SQL string is executable without executing it. Isn't it?
why don't use generated class files rather than typing native SQL?
dslContext.selectFrom(GENERATED_TABLE)...
PS: If you use JOOQ DSL(with generated classes) for generating SQL it would be work but not completely in some cases if you do mistakes even on generated classes (relations or some aggregate functions) it will not complain about it and will compile successfully.
Older versions of jOOQ did not implement meta data lookups in the parser, or only to some limited extent, and just accepted all valid identifiers. Starting with jOOQ 3.14, there will be an improved implementation as of:
https://github.com/jOOQ/jOOQ/issues/9061
You will need to provide jOOQ with a Configuration.metaProvider() (it defaults to the JDBC DatabaseMetaData backed implementation. You might prefer using generated code), and then jOOQ will try to resolve all identifiers.
Prior to jOOQ 3.14, you could implement a VisitListener which traverses the parsed SQL query, and validate all the identifiers yourself.
Using Java 11 and JDBC.
Having PostgreSQL table "employee":
I need to have an ability to select data, but I don't know in advance, what WHERE conditions would be used.
It could be:
SELECT * FROM employee WHERE job_name='PRESIDENT';
SELECT * FROM employee WHERE job_name='PRESIDENT' OR salary>6000;
SELECT * FROM employee WHERE salary<5000 AND manager_id=68319;
Writing all possible SQL in the code, would take a lot of time.
Probably, there is some library, that already has implementation for it.
Try sqlBuilder [http://sqlobject.org/SQLBuilder.html]. it has support to build dynamic where clauses based on condition. something like below
var query = SQL
.SELECT("*")
.FROM("employee")
.WHERE()
._If(job_name=="PRESIDENT", "job_name = {0}", job_name)
.ORDER_BY("job_name");
We have a data table where it has a function based index (database is Oracle). But in our Java EE ejb application, system accesses the data using jpa queries.
But in order to force the oracle to use the function based index instead of doing a full table scan, I need a way to tell the jpa container to generate the sql with the function defined in the index in the WHERE clause of the sql query.
As far as I know, we have to use native queries for creating customizations in the generated queries like that. But in order to use native queries we have to do many code changes.
Could anyone please suggest any other work around for solving this issue?
Index: (We needed to enforce unique constraint for Dev_Id + Dev_Type, but sometimes Dev_Id can be null while Dev_Type can be duplicated.)
(NVL2(Dev_Id, Dev_Id, NULL), NVL2(Dev_Id, Dev_Type, NULL))
Query we need: (In order to use the index)
Select * from some_table where NVL2(Dev_Id, Dev_Id, NULL) = 'some_val';
Container generated query:
Select * from some_table where Dev_Id = 'some_val';
Maybe creating a view and having JPA go through that is an option?
CREATE VIEW SOME_VIEW AS SELECT SOME_TABLE.*,
NVL2(Dev_Id, Dev_Id, NULL) AS NVL_DEV_ID FROM SOME_TABLE;
SELECT * FROM SOME_VIEW WHERE NVL_DEV_ID = ?
Or a virtual column on the table that evaluates to the function?
JPA 2.1 includes a FUNCTION operator that allows to invoke DB-specific functions:
from SomeEntity where function('NVL2', devId, devId, null) = 'some_val';
If you don't have JPA 2.1 available but are using Eclipselink >= 2.4, you can also use FUNCTION, as it is available as a Eclipselink extension.
If you have Eclipselink 2.3.x, you do not have FUNCTION, but you can use the equivalent FUNC that is available as a Eclipselink extension.
I have an embeded derbyDB in my app, and I am currently testing my code.
If I send the following SQL code
set current schema [newSchemaName];
from ij then I can set the schema and the response from the DB of
show tables;
will report only the tables that exist in the newSchemaName previously identified (although this doesn't always seem to work!)
If I do a similar thing from java code and then perform a
getCurrentConection.getSchema();
The value returned from the above never proposes the newSchemaName passed in the SQL (although if I use a prepared statement it returns the newSchemaName as expected).
Here is some extra background info...
I have the default database name 'derbyTest' and create 3 other schemas.
Admin
S1
S2
to logically separate/hide information from users that they don't need to know about
I need to change schemas during operation (eg: an admin will change schemas if required to view more 'delicate' info).
To do this I created a method for setSchema(String newSchemaName), that creates the schema (if it doesn't already exist) then connects to it.
However after running the code snippet
/**
*method to change to a given schema
*#param newSchemaName the new schema to change to
/
public void SetSchema(String newSchemaName){
String sql = newSchemaName.toUpperCase();//make sure the newSchemaName is in upper case.
ResultSet rs;
try
{
rs = this.sendQry("select schemaName from sys.sysschemas where schemaname = '" + sql + "'");//does this schema exist in the DB
if (rs.next())
{//the schema already exists
//send some messages to the user about the change of schema
errLog.setDevError(1, "derbyDB schema" +sql +" already exists ");
errLog.add(2, "connecting to " + sql);
//next line create the SQL for changing to the newSchemaName supplied
this.sendSQL("set current schema " + sql);//connect to the schema
//log a message to display the current schema in the DB
//this next log never shows a change to the newSchemaName unless
//I use a prepared statement in my java code.
errLog.add(1, "current DB schema is " + getCurrentConection.getSchema();
}
else{//the schema does not exist
//send a message to the user and output log
errLog.setDevError(1, "derbyDB schema" +sql +" does not exist ");
//code to send message asking if user wants to create the new schema....
}
}//end try
catch{
//catch errors
}
}//end method
If I look at the docs http://db.apache.org/derby/docs/dev/ref/rrefsqlj32268.html for setting the schema my SQL is correct, and the code works if I run directly from ij.
I know that there are some differences between ij and the client side (functions such as describe don't work in the client, you need to fart about with meta data instead).
Is it the same case for the set schema statment. Or does this only work from a prepared statement, which I'm about to test.
If so that begs the question of why I can only change the schema from a prepared statement?
Thoughts and comments greatefully accepted.
David
edit:
A prepared statement works for changing the schema. so now it is only the second question that stands. why the difference between a prepared statement and a normal statement... time for google I think?
edit:
I don't know if it would make a difference but I am on a windows platform, using the standard JDK (6), and eclipse indigo running jUnit test inside eclipse. I can also test on Linux(ubuntu) with opendJDK if it may help to troubleshoot.
I'm not sure what your question is.
You can specify the schema explicitly in your table references, as in:
SELECT * FROM S1.TABLE_NAME
or
UPDATE S2.TABLE_NAME SET COL1=VALUE1
etc.
Or, if you prefer, you can omit the schema name from your table references, saying merely:
SELECT * FROM TABLE_NAME
or
UPDATE TABLE_NAME SET COL1=VALUE1
etc., in which case you will need to establish an implicit schema for those statements, either by issuing a SET SCHEMA statement, or by using the existing default schema, which matches your username when you log in.
I think your question about prepared statements versus non-prepared statements has to do with the fact that, if you don't specify an explicit schema, then the default schema name is established when the statement is prepared.
If it were me, and I cared about what schema I was using, I would specify the schema explicitly in all my table references in all my SQL statements, and then I'd be sure which schema I was using when.