I have the following java code that uses hibernate predicates to return search reusults from my Appointment MYSQL table.
public List<Appointment> getSearchResults(String client, AppointmentSearchRequest searchRequest, Predicate completePredicate) {
List<Appointment> searchResults = new ArrayList<>();
EntityManager entityManager = null;
try {
entityManager = entityManagement.createEntityManager(client);
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Appointment> query = builder.createQuery(Appointment.class);
Root<Appointment> from = query.from(Appointment.class);
CriteriaQuery<Appointment> selectQuery = query.select(from);
selectQuery = selectQuery.where(completePredicate);
searchResults = entityManager.createQuery(selectQuery).setFirstResult(searchRequest.getIndex()).setMaxResults(searchRequest.getSize()).getResultList();
}catch (Exception e){
//
}
return searchResults;
}
When I run this code, at the following line:
searchResults = entityManager.createQuery(selectQuery).setFirstResult(searchRequest.getIndex()).setMaxResults(searchRequest.getSize()).getResultList();
I am getting the error:
17:20:27,730 ERROR [org.hibernate.hql.internal.ast.ErrorCounter] (http-/127.0.0.1:8080-2) Invalid path: 'generatedAlias1.title'
17:20:27,734 ERROR [org.hibernate.hql.internal.ast.ErrorCounter] (http-/127.0.0.1:8080-2) Invalid path: 'generatedAlias1.title': Invalid path: 'generatedAlias1.title'
at org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:119) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
What could be causing this error?
Ironically i just had exactly the same issue some days ago: the problem is your path "generatedAlias1.title" which is understandable in JPQL as a dereference of the field title from an inner entity referenced with generatedAlias1.
Unluckily this complex path in a single String cannot be understood by the CriteriaBuilder.
This path is normally described within the Predicate element which you are passing here as an argument to your method getSearchResults with name completePredicate ... ( the problem is that you did not tell us how you are creating this predicate )
So you need to refactor the way in which you declare this path, eventually using the class javax.persistence.criteria.Path and calculating it with this method
final private <V> Path<V> getPath(Root<T> root, String attributeName) {
Path<V> path = null;
for (String part : attributeName.split("\\.")) {
path = (path == null) ? root.get(part) : path.get(part);
}
return path;
}
Where you will pass the property from of your method getSearchResults as the argument root, and the string containing "generatedAlias1.title" as attributeName; then you can re-declare your predicate as an instance of Predicate which is acting on this path here returned.
I hope I have been clear enough
Try checking your Query
See this answer. It might be just as simple as checking your query aliases. Make sure that they match, otherwise the query won't compile at all. You didn't list your full query here, so I can't tell if it's incorrect or not.
Related
I would like to avoid passing SPARQL queries around as Strings. Therefore I use Jena's API for creating my queries. Now I need a PropertyPath in my query, but I can't find any Java class supporting this. Can you give me a hint?
Here's some example code where I would like to insert this (Jena 3.0.1):
private Query buildQuery(final String propertyPath) {
ElementTriplesBlock triplesBlock = new ElementTriplesBlock();
triplesBlock.addTriple(
new Triple(NodeFactory.createURI(this.titleUri.toString()),
//How can I set a property path as predicate here?
NodeFactory.???,
NodeFactory.createVariable("o"))
);
final Query query = buildSelectQuery(triplesBlock);
return query;
}
private Query buildSelectQuery(final ElementTriplesBlock queryBlock) {
final Query query = new Query();
query.setQuerySelectType();
query.setQueryResultStar(true);
query.setDistinct(true);
query.setQueryPattern(queryBlock);
return query;
}
You can use PathFactory to create property paths
Consider the graph below:
#prefix dc: <http://purl.org/dc/elements/1.1/>.
#prefix ex: <http://example.com/>.
ex:Manager ex:homeOffice ex:HomeOffice
ex:HomeOffice dc:title "Home Office Title"
Suppose you want to create a pattern like:
?x ex:homeOffice/dc:title ?title
The code below achieves it:
//create the path
Path exhomeOffice = PathFactory.pathLink(NodeFactory.createURI("http://example.com/homeOffice"));
Path dcTitle = PathFactory.pathLink(NodeFactory.createURI("http://purl.org/dc/elements/1.1/title"));
Path fullPath = PathFactory.pathSeq(exhomeOffice,dcTitle);
TriplePath t = new TriplePath(Var.alloc("x"),fullPath,Var.alloc("title"));
I have to do this flexible search query in a service Java class:
select sum({oe:totalPrice})
from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk}
join OrderEntry as oe on {or.pk}={oe.order}}
where {or:versionID} is null and {or:orderType} in (8796093066999)
and {or:company} in (8796093710341)
and {or:pointOfSale} in (8796097413125)
and {oe:ecCode} in ('13','14')
and {or:yearSeason} in (8796093066981)
and {os:code} not in ('CANCELED', 'NOT_APPROVED')
When I perform this query in the hybris administration console I correctly obtain:
1164.00000000
In my Java service class I wrote this:
private BigDecimal findGroupedOrdersData(String total, String uncDisc, String orderPromo,
Map<String, Object> queryParameters) {
BigDecimal aggregatedValue = new BigDecimal(0);
final StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("select sum({oe:").append(total).append("})");
queryBuilder.append(
" from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk} join OrderEntry as oe on {or.pk}={oe.order}}");
queryBuilder.append(" where {or:versionID} is null");
if (queryParameters != null && !queryParameters.isEmpty()) {
appendWhereClausesToBuilder(queryBuilder, queryParameters);
}
queryBuilder.append(" and {os:code} not in ('");
queryBuilder.append(CustomerOrderStatus.CANCELED.getCode()).append("', ");
queryBuilder.append("'").append(CustomerOrderStatus.NOT_APPROVED.getCode()).append("')");
FlexibleSearchQuery query = new FlexibleSearchQuery(queryBuilder.toString(), queryParameters);
List<BigDecimal> result = Lists.newArrayList();
query.setResultClassList(Arrays.asList(BigDecimal.class));
result = getFlexibleSearchService().<BigDecimal> search(query).getResult();
if (!result.isEmpty() && result.get(0) != null) {
aggregatedValue = result.get(0);
}
return aggregatedValue;
}
private void appendWhereClausesToBuilder(StringBuilder builder, Map<String, Object> params) {
if ((params == null) || (params.isEmpty()))
return;
for (String paramName : params.keySet()) {
builder.append(" and ");
if (paramName.equalsIgnoreCase("exitCollection")) {
builder.append("{oe:ecCode}").append(" in (?").append(paramName).append(")");
} else {
builder.append("{or:").append(paramName).append("}").append(" in (?").append(paramName).append(")");
}
}
}
The query string before the search(query).getResult() function is:
query: [select sum({oe:totalPrice}) from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk}
join OrderEntry as oe on {or.pk}={oe.order}} where {or:versionID} is null
and {or:orderType} in (?orderType) and {or:company} in (?company)
and {or:pointOfSale} in (?pointOfSale) and {oe:ecCode} in (?exitCollection)
and {or:yearSeason} in (?yearSeason) and {os:code} not in ('CANCELED', 'NOT_APPROVED')],
query parameters: [{orderType=OrderTypeModel (8796093230839),
pointOfSale=B2BUnitModel (8796097413125), company=CompanyModel (8796093710341),
exitCollection=[13, 14], yearSeason=YearSeasonModel (8796093066981)}]
but after the search(query) result is [null].
Why? Where I wrong in the Java code? Thanks.
In addition, if you want to disable restriction in your java code. You can do like this ..
#Autowired
private SearchRestrictionService searchRestrictionService;
private BigDecimal findGroupedOrdersData(String total, String uncDisc, String orderPromo,
Map<String, Object> queryParameters) {
searchRestrictionService.disableSearchRestrictions();
// You code here
searchRestrictionService.enableSearchRestrictions();
return aggregatedValue;
}
In the above code, You can disabled the search restriction and after the search result, you can again enable it.
OR
You can use sessionService to execute flexible search query in Local View. The method executeInLocalView can be used to execute code within an isolated session.
(SearchResult<? extends ItemModel>) sessionService.executeInLocalView(new SessionExecutionBody()
{
#Override
public Object execute()
{
sessionService.setAttribute(FlexibleSearch.DISABLE_RESTRICTIONS, Boolean.TRUE);
return flexibleSearchService.search(query);
}
});
Here you are setting DISABLE RESTRICTIONS = true which will run the query in admin context [Without Restriction].
Check this
Better i would suggest you to check what restriction exactly applying to your item type. You can simply check in Backoffice/HMC
Backoffice :
Go to System-> Personalization (SearchRestricion)
Search by Restricted Type
Check Filter Query and analysis your item data based on that.
You can also check its Principal (UserGroup) on which restriction applied.
To confirm, just check by disabling active flag.
Query in the code is running not under admin user (most likely).
And in this case the different search Restrictions are applied to the query.
You can see that the original query is changed:
start DB logging (/hac -> Monitoring -> Database -> JDBC logging);
run the query from the code;
stop DB logging and check log file.
More information: https://wiki.hybris.com/display/release5/Restrictions
In /hac console the admin user is usually used and restrictions will not be applied because of this.
As the statement looks ok to me i'm going to go with visibility of the data. Are you able to see all the items as whatever user you are running the query as? In the hac you would be admin obviously.
I am trying to use querydsl for building dynamic queries for dynamic schemas. I am trying to get just the query instead of having to actually execute it.
So far I have faced two issues:
- The schema.table notation is absent. Instead I only get the table name.
- I have been able to get the query but it separates out the variables and puts '?' instead which is understandable. But I am wondering if there is some way to get fully materialized query including the parameters.
Here is my current attempt and result(I am using MySQLTemplates to create the configuration):
private SQLTemplates templates = new MySQLTemplates();
private Configuration configuration = new Configuration(templates);
String table = "sometable"
Path<Object> userPath = new PathImpl<Object>(Object.class, table);
StringPath usernamePath = Expressions.stringPath(userPath, "username");
NumberPath<Long> idPath = Expressions.numberPath(Long.class, userPath, "id");
SQLQuery sqlQuery = new SQLQuery(connection, configuration)
.from(userPath).where(idPath.eq(1l)).limit(10);
String query = sqlQuery.getSQL(usernamePath).getSQL();
return query;
And what I get is:
select sometable.username
from sometable
where sometable.id = ?
limit ?
What I wanted to get was:
select sometable.username
from someschema.sometable
where sometable.id = ?
limit ?
Update: I came up with this sort of hack to get parameters materialized(Not ideal and would love better solution) But still could not get Schema.Table notation to work:
Hack follows. Please suggest cleaner QueryDsl way of doing it:
String query = cleanQuery(sqlQuery.getSQL(usernamePath));
private String cleanQuery(SQLBindings bindings){
String query = bindings.getSQL();
for (Object binding : bindings.getBindings()) {
query = query.replaceFirst("\\?", binding.toString());
}
return query;
}
To enable schema printing use the following pattern
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
SQLTemplates subclasses were used before, but since some time the builder pattern is the official way to customize the templates http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html#d0e904
And to enable direct serialization of literals use
//configuration level
configuration.setUseLiterals(true);
//query level
configuration.setUseLiterals(true);
Here is a full example
// configuration
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
Configuration configuration = new Configuration(templates);
// querying
SQLQuery sqlQuery = new SQLQuery(connection, configuration)
.from(userPath).where(idPath.eq(1l)).limit(10);
sqlQuery.setUseLiterals(true);
String query = sqlQuery.getSQL(usernamePath).getSQL();
If you always just want the SQL query string out, move setUseLiterals from query to configuration.
Concerning the usage of Querydsl expressions the usage of code generation like documented here is advised http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html
It will make your code typesafe, compact and readable.
If you want to try Querydsl without code generation you can replace
Path<Object> userPath = new PathImpl<Object>(Object.class, variable);
with
Path<Object> userPath = new RelationalPathBase<Object>(Object.class, variable, schema, table);
When working with QueryDSL, you must provide a template for the database platform to build the query for. I see you are already are doing this here:
private SQLTemplates templates = new MySQLTemplates();
private Configuration configuration = new Configuration(templates);
To make the schema name appear in the generated query, the only way I have found to do this is (there may be an easier way) is to extend the template class and explicitly call this.setPrintSchema(true); inside the constructor. Here is a class that should work for MySql:
import com.mysema.query.sql.MySQLTemplates;
public class NewMySqlTemplates extends MySQLTemplates {
public NewMySqlTemplates() {
super('\\', false);
}
public NewMySqlTemplates(boolean quote) {
super('\\', quote);
}
public NewMySqlTemplates(char escape, boolean quote) {
super(escape, quote);
this.setPrintSchema(true);
}
}
Then simply use this NewMySqlTemplates class in place of the MySQLTemplates class like this:
private SQLTemplates templates = new NewMySQLTemplates();
private Configuration configuration = new Configuration(templates);
I have this working using PostgresTemplates, so I may have a typo or mistake in the NewMySqlTemplates class above, but you should be able to get it to work. Good luck!
I am using Apache Jackrabbit as a database.
In my case, root node has numbers of child nodes(only at depth 1).
All child node has unique name, i.e., some Integer.
Each child Node have some properties that I have used further.
My task
I have to take top 10 nodes whose keys(integer values) are minimum.
My thinking
To achieve above goal, I make a query that sorts the keys of all child nodes, and pick top 10. Then by using that keys, I get all corresponding nodes, and after working, delete all that key/value pairs.
For that I searched a lot on the internet how to run the query. Can you please tell me how to run query on apache jackrabit. It is good, if you explain with example.
Edit no. 1
public class JackRabbit {
public static void main(String[] args) throws Exception {
try {
Repository repository = JcrUtils.getRepository("http://localhost:4502/crx/server");
javax.jcr.Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
Node root = session.getRootNode();
// Obtain the query manager for the session via the workspace ...
javax.jcr.query.QueryManager queryManager = session.getWorkspace().getQueryManager();
// Create a query object ...
String expression = "select * from nt:base where name= '12345' ";
javax.jcr.query.Query query = queryManager.createQuery(expression, javax.jcr.query.Query.JCR_SQL2);
// Execute the query and get the results ...
javax.jcr.query.QueryResult result = query.execute();
session.logout();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Exception
javax.jcr.query.InvalidQueryException: Query:
select * from nt:(*)base where name= '12345'; expected: <end>
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at org.apache.jackrabbit.spi2dav.ExceptionConverter.generate(ExceptionConverter.java:69)
at org.apache.jackrabbit.spi2dav.ExceptionConverter.generate(ExceptionConverter.java:51)
at org.apache.jackrabbit.spi2dav.ExceptionConverter.generate(ExceptionConverter.java:45)
at org.apache.jackrabbit.spi2dav.RepositoryServiceImpl.executeQuery(RepositoryServiceImpl.java:2004)
at org.apache.jackrabbit.jcr2spi.WorkspaceManager.executeQuery(WorkspaceManager.java:349)
at org.apache.jackrabbit.jcr2spi.query.QueryImpl.execute(QueryImpl.java:149)
at jackrabbit.JackRabbit.main(JackRabbit.java:36)
I want to write a query of below scenereo
Here nodes having integer value have some properties. I want to sort these nodes by their integer values, and extract top 50 nodes for further processing.
Help me in that.
You should quote your node type name in JCR-SQL2:
select * from [nt:base]
This is one of the main differences between JCR-SQL and JCR-SQL2. Besides, name is a dynamic operand taking a selector argument. So a better way to write your query would be this:
select * from [nt:base] as b where name(b) = '12345'
You have different ways of executing your queries depending on the query language you want to use.
Take a look at this code for some simple query using only the API and not SQL like string queries.
You can take a look at JBoss Modeshape documentation for examples too since it is another JCR 2.0 implementation.
I hope this will help you to execute the query:
public FolderListReturn listFolder(String parentNode, String userid,String password) {
System.out.println("getting folders and files from = "+parentNode+" of user : "+userid);
SessionWrapper sessions =JcrRepositoryUtils.login(userid, password);
Session jcrsession = sessions.getSession();
Assert.notNull(name);
FolderListReturn folderList1 = new FolderListReturn();
ArrayOfFolders folders = new ArrayOfFolders();
try {
javax.jcr.query.QueryManager queryManager;
queryManager = jcrsession.getWorkspace().getQueryManager();
String expression = "select * from [nt:folder] AS s WHERE ISCHILDNODE(s,'"+name+"')and CONTAINS(s.[edms:owner],'*"+userid+"*') ORDER BY s.["+Config.EDMS_Sorting_Parameter+"] ASC";
javax.jcr.query.Query query = queryManager.createQuery(expression, javax.jcr.query.Query.JCR_SQL2);
javax.jcr.query.QueryResult result = query.execute();
for (NodeIterator nit = result.getNodes(); nit.hasNext();) {
Node node = nit.nextNode();
Folder folder = new Folder();
folder=setProperties(node,folder,userid,password,jcrsession,name);
folders.getFolderList().add(folder);
}
folderList1.setFolderListResult(folders);
folderList1.setSuccess(true);
} catch (Exception e) {
e.printStackTrace();
}finally{
//JcrRepositoryUtils.logout(sessionId);
}
return folderList1;
}
I have a property oldStatus and newStatus in my object and when I try to run a query on the object where newStart = approved. I am getting an error.
Seems like the newStatus is being treated as new Status() and getting an exception that object Status not found.
Anyone with similar issue? and possible solution.
Query query = pm.newQuery(Inquiry.class, " newStatus == 'CANCELED' ");
or
Query query = pm.newQuery(Inquiry.class);
query.setFilter("newStatus == statusParam");
query.declareParameters("String statusParam");
List<Inquiry> pis = (List<Inquiry>)query.execute("CANCELLED");
CreatorExpression defined with class of Status yet this class is not found
stausParam != statusParam .. typo ?