How can I get Toplink generated query by using getTranslatedSQLString? - java

So what I'm doing is creating a subquery that gets a list of ID values, then the main query gets all the necessary values and adds ordering.
What I have is this:
ReportQuery querySub = new ReportQuery(Predmet.class, generatedExpression);
querySub.addAttribute("m_id");
DatabaseRow row = new DatabaseRow();
querySub.prepareCall(getSession(), row);
// This part is the problem
String sql = querySub.getTranslatedSQLString(getSession(), row);
The problem with this code is that it doesn't return TranslatedSQLString, it returns the same result as querySub.getSQLString(). Now in all the example code I saw, they either instanced row as a new object or didn't bother to write from where they got the reference but whatever the case, this doesn't work (TopLink version issue?). I'm guessing I need to populate the DatabaseRow object myself, but I can't find any example online.

I didn't manage to find any way to do this by using getTranslatedSQLString. I suppose the DatabaseRow needs to be populated, but I have yet to find the proper way. For now, I'm using "bruteforce" substitution, I "memorize" all of my parameters and do a find/replace on each "?" sign in the query.

you need get session like this:
JpaHelper.getDatabaseSession(getEntityManager().getEntityManagerFactory());
The Database that you need is:
TypedQuery<T> typedQuery = getEntityManager().createQuery(cq);
DatabaseQuery databaseQuery = typedQuery.unwrap(JpaQuery.class).getDatabaseQuery();
So the final example is:
Session session = JpaHelper.getDatabaseSession(getEntityManager().getEntityManagerFactory());
DatabaseQuery databaseQuery = null;
if(typedQuery instanceof EJBQueryImpl)
databaseQuery = ((EJBQueryImpl<T>)typedQuery).getDatabaseQuery();
else
databaseQuery = typedQuery.unwrap(JpaQuery.class).getDatabaseQuery();
sql = databaseQuery.getTranslatedSQLString(session, databaseQuery.getTranslationRow());
That work for me.

Related

Apache Lucene Query Iterate through all queries / terms

I have an interface that enforces implementing classes to define and implement a function that returns an org.apache.lucene.search.Query. These classes create various queries like TermQuery, PhraseQuery, etc. Is it possible to take the org.apache.lucene.search.Query that gets returned and iterate over all of the queries and terms it's comprised of?
public interface BaseQuery {
public Query getQuery();
default Query toQuery() {
Query query = getQuery();
// iterate through Query and do things to each term
return query;
}
}
public class ContainsQuery implements BaseQuery {
#Override
protected Query getQuery() {
PhraseQuery.Builder queryBuilder = new PhraseQuery.Builder();
queryBuilder.add(new Term("field", "value");
return queryBuilder.build();
}
}
As you can't update the changes (setTerms or similar), not even in this implementation (PhraseQuery), maybe this works.
You could first retrieve them, and loop over them. Whatever modification you wish to do, update the term or create a new one, or even discard those unwanted.
Then, assign query to a newly constructed object with the modified terms. Something like a manual update/set for a Query object. In the example I just add the terms to the builder, but you could include the previous parameters as well (slop, ...).
default Query toQuery()
{
Query query = getQuery();
Term[] terms= query.getTerms();
List<Term> modifiedTerms = new ArrayList<>();
for (Term t : terms)
{
/*Your modifications here f.e --> you copy one, create two terms and discard one
Term toAdd=null;
toAdd= t.clone();
...
toAdd = new Term((t.field()+"suffix"), t.text());
...
toAdd = new Term("5","6");
...
(do nothing-discard)
if (toAdd!=null)
modifiedTerms.add(toAdd);*/
}
PhraseQuery.Builder builder = new PhraseQuery.Builder();
for (int i=0;i<modifiedTerms.size();i++)
builder.add(modifiedTerms.get(i),i);
query = builder.build();
return query;
}
/* override the reference and assign a new one very similar to s
set/update, if those where implemented.
The last query will be erased on the next GC
so there's not a big gap here. Also this is most surely
a not needed micro-optimization, no worries. */
The way to do this is using the QueryTermExtractor.
WeightedTerm[] terms = QueryTermExtractor.getTerms(query);
for (WeightedTerm term : terms) {
System.out.println("THE TERM: " + term.getTerm());
}
The issue I was having is that all examples I found were calling .getTerms() on a org.apache.lucene.search.Query but .getTerms() seems to no longer be implemented on the base Query class.
Also, #aran's suggested approach of constructing a new Query object is an appropriate method to "modifying" the terms on an already constructed immutable Query object.

How to I remove L from Long field's values in java spring

I put query param for my list services for example:
tablename/list?query=id:10
it is running but I added other param
'personTNo'
tablename/list?query=id:10&personTNo=101035678
id is Integer but personTNo is Long
when I try to this sql returns select * from TABLENAME WHERE personTNo=10L
but this I want to return without 'L' for Long value. It is my code's a bit section in RepositoryCustom class
public List<TABLENAME> getTable(Specification aTablenameSpec) {
CriteriaBuilder builder = mEntityManager.getCriteriaBuilder();
CriteriaQuery<Object> query = builder.createQuery();
Root<TABLENAME> root = query.from(TABLENAME.class);
String queryWhere = null;
org.hibernate.query.Query hibernateQuery = null;
Predicate predicate = aTablenameSpec.toPredicate(root, query, builder);
if (predicate != null) {
query.where(predicate);
query.select(root);
TypedQuery<Object> typedQuery = mEntityManager.createQuery(query);
hibernateQuery = typedQuery.unwrap(org.hibernate.query.Query.class);
String queryString = hibernateQuery.getQueryString();
This row returns with L result, How to remove 'L' value in sql
Use INTEGER() function in the sql query. You can also try CAST() or CONVERT() functions in the query
Based on the problem description and code, it seems safe to assume the tech stack includes: JPA and Spring Data JPA.
And I understand that you want to remove the Long value L suffixes, but it's not clear if that's because the suffixes are causing a problem or exactly why you want the suffixes removed.
I only say that because the example query string appears to be a valid JPA query:
select * from TABLENAME WHERE personTNo = 10L
JPA support for the use of literal values in queries includes support for standard Java numeric (integer/long/float/double) literal value syntax.
Which means the L suffix on the literal Long value of personTNo, as defined in your query (10L), is legitimate, valid, and should not cause a problem.
Please let me know if I've missed the point, made an incorrect assumption, or overlooked something, and I will follow up.

Oracle ADF When Selecting Multiple Rows, RowSetIterator Does Not Populate on First Method Invocation

Uncertain how best to word the title, but here's the gist.
The goal is to retrieve all selected rows of a table and manipulate them. The problem I'm bumping into is that the RowSetIterator doesn't get populated the first time the method within my backing bean is invoked. It does get populated when invoked a second time.
How do I go about getting it to work properly on the first invocation?
Doubtless I'm not being perfectly clear, please let me know if you require any additional information. Here's a snippet of the bean method:
public String deleteSelectedQueries()
{
JSFUtils.addInformationMessage("Delete");
RowKeySet selectedQueries =
getSavedQueriesByUserTable().getSelectedRowKeys();
Iterator selectedQueriesIter = selectedQueries.iterator();
DCBindingContainer bindings =
(DCBindingContainer) BindingContext.getCurrent().getCurrentBindingsEntry();
DCIteratorBinding savedQueriesByUserIter =
bindings.findIteratorBinding("SavedQueriesByUserROVOIterator");
RowSetIterator savedQueriesByUserRowSetIterator =
savedQueriesByUserIter.getRowSetIterator();
while (selectedQueriesIter.hasNext())
{
Key key = (Key) ((List) selectedQueriesIter.next()).get(0);
Row currentRow = savedQueriesByUserRowSetIterator.getRow(key);
System.out.println(currentRow.getAttribute("QueryName"));
}
return null;
}
}
Any ideas?
Thanks!
This code looks good to me.
The problem may come from <af:table> tag, make sure you have these tags removed:
selectedRowKeys="#{bindings.SavedQueriesByUserROVO.collectionModel.selectedRow}"
selectionListener="#{bindings.SavedQueriesByUserROVO.collectionModel.makeCurrent}"

Using a NamedParamterJdbcTemplate object to specify a mysql field and value to query on

I am currently in the process of learning the Java Spring Framework, and I am having difficulty understanding why the following query is failing to return any results from the database.
I am ultimately trying to create a where method in my OffersDAO class that allows my to query on a specific field, for a specific value.
public List<Offer> where(String field, String value){
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("field", field);
params.addValue("value", value);
String sql = "select * from offers where :field = :value";
return jdbc.query(sql, params, new RowMapper<Offer>(){
public Offer mapRow(ResultSet rs, int arg1) throws SQLException {
Offer offer = new Offer();
offer.setId(rs.getInt("id"));
offer.setName(rs.getString("name"));
offer.setText(rs.getString("text"));
offer.setEmail(rs.getString("email"));
return offer;
}
});
}
I am able to successfully query the database for results when I specify the field explicitly, as follows:
String sql = "select * from offers where name = :value";
Obviously there is something wrong with specifying the field name dynamically. My guess is it is most likely due to the fact that the field key is being inserted as a mysql string (with ''), when in fact mysql expects a column name for the :field placeholder.
My questions are as follows:
Is there a way to accomplish what I am attempting to do above, using the jdbc NamedParameterJdbcTemplate class?
If I cannot accomplish the above, by what means can I?
Thank you
Edit: No exceptions are thrown. In the case when I am attempting to supply the column name, a empty result set is returned.
You can't specify the field name in a parameter - only the field value. Since you know the DB schema when you're writing the code, this shouldn't be much of a problem.
What about include all possible fields in the filter but restricting their usage by field name param. Like this:
select * from offers where
('name'=:field and name = :value)
OR
('field2'=:field and field2 = :value)
OR
('field3'=:field and field3 = :value)
I don't know how You can implement it with spring (I mean use variable column names) but I can suggest to use the following principle.
Keep your query like template:
String sql = "select * from offers where ##field = :value";
And every time before execution replace ##value parameter with the column You want.
And then You are gone.

Constructing DTO:s with Querydsl and ConstructorExpression.create()

I have a problem involving querydsl and DTO:s
I have some query object:
QPerson person = QPerson.person;
QExamCode examCode = QExamCode.examCode;
QExamGrade examGrade = QExamGrade.examGrade;
QProgram gradeProgram = examGrade.program;
From them I try to query and list instances of a DTO class (that is not an entity) that is called CompletedCreditsSummary.
CompletedCreditsSummary has a constructor which takes: Long,Long,Float.
JPQLQuery query = new JPAQuery(manager);
query = query.from(person, examCode, examGrade);
query = query.where(person.studies.examGrades.contains(examGrade).and(examGrade.examCode.eq(examCode)).and(examGrade.passed.isTrue()));
I am able to do this (Without group by and with CompletedCreditsSummary requiering all the parameters it needs to be able to create person and program objects, in this case simplified to person.id and program.id)
ConstructorExpression.create(CompletedCreditsSummary.class,person.id,program.id,examCode.credits);
return query.list(completedCreditsSummaryExpression);
This works. But when I want to add this to the query:
query.groupBy(person, examGrade.program);
and create CompletedCreditssummary with examCode.credits.sum() i.e.
ConstructorExpression.create(CompletedCreditsSummary.class,person.id,gradeProgram.id,examCode.credits.sum());
instead of
ConstructorExpression.create(CompletedCreditsSummary.class,person.id,gradeProgram.id,examCode.credits);
I get a: java.lang.IllegalArgumentException: argument type mismatch.
The question here is what the difference between examCode.credits (NumberPath) and examcode.credits.sum() (NumberExpression) and what I could do to solve my problem.
As I am learning querydsl by trial and error there is probably something fundamental that I have overlooked. Would really appreciate any help!
Regards Rasmus
EDIT: Preferably I would something like this to work (with group by and CompletedCreditsSummary constructor taking Person,Program,Float.):
ConstructorExpression<Person> personExpression = ConstructorExpression.create(Person.class,person.id);
ConstructorExpression<Program> programExpression = ConstructorExpression.create(Program.class,gradeProgram.id);
ConstructorExpression<CompletedCreditsSummary> completedCreditsSummaryExpression = ConstructorExpression.create(CompletedCreditsSummary.class,personExpression,programExpression,examCode.credits.sum());
EDIT: Got it to work by having the CompletedCreditsSummary Constructor accepting: Long,Long,Number. That is I changed Float to Number. This is not an ideal solution but at least it works.
Try something like this
JPAQuery query = new JPAQuery(manager);
query.from(person, examCode, examGrade)
.where(
person.studies.examGrades.contains(examGrade),
examGrade.examCode.eq(examCode),
examGrade.passed.isTrue())
.groupBy(person, examGrade.program)
.list(ConstructorExpression.create(
CompletedCreditsSummary.class,
person, examGrade.program, examCode.credits.sum()));
You need to make sure that the argument for ConstructorExpression after the class are compatible with the arguments to the constructor you want to invoke. Replacing entities with ids caused your problems.

Categories