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"));
Related
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.
I had gotten the code to work to search for folders and retrieve properties. Ref: Search folder hierarchy in FileNet for a particular folder
I am trying to retrieve the class name of the folder object so as to differentiate between different types of docs that will get stored in custom folders.
I iterated thru the Properties collection, but the name of the class isn't a property.
String sqlStatement = "SELECT * FROM [Folder] WHERE ([FolderName] LIKE '%MyFolder%')";
SearchSQL sqlObject = new SearchSQL(sqlStatement);
RepositoryRowSet rowSet = searchScope.fetchRows(sqlObject, null, null, new Boolean(true));
Iterator iter = myRows.iterator();
while (iter.hasNext()) {
RepositoryRow row = (RepositoryRow) iter.next();
String folderID = row.getProperties().getIdValue("ID").toString();
}
I tried row.getClass() but that just returns: RepositoryRowImpl
If you use the * in your SELECT clause then the repository row object will contain all the properties of the object. This will also include a property called This. This property is a reference to the object that is returned. Therefore you can use the following code to fetch the class of the folder:
EngineObject eo = row.getProperties().getEngineObjectValue("This");
String className = eo.getClassName();
Instead of the * you can also explicitly select This. In that case your query will be like this:
String sqlStatement = "SELECT This,Id FROM [Folder] WHERE ([FolderName] LIKE '%MyFolder%')";
This will limit the amount of data that is fetched from the server.
I'm trying to create an sql sentence using querydsl. What I'm trying to get is:
SELECT P.KEY, COUNT(P.VALUE)
FROM RESOURCES R JOIN PROPERTIES P ON R.ID = P.ID
WHERE P.KEY = "key" AND p.VALUE = "value"
GROUP BY P.VALUE;
I've tried to write some querydsl code:
String s = queryFactory
.query()
.from(QResource.resource)
.join(QProperty.property)
.where(QResource.resource.properties.any().key.eq("key").and(QResource.resource.properties.any().value.eq("value")))
.groupBy(QProperty.property.value)
.select(QProperty.property.key, QProperty.property.value.count())
.toString();
I'm guessing it can be simplified and by other hand I don't quite see if it's well querydsl-coded.
Any ideas?
A more simplified version would be:
QResource r = QResource.resource;
QProperty p = QProperty.property;
queryFactory
.select(p.key, p.value.count())
.from(r)
.join(p).on(r.id.eq(p.id))
.where(p.key.eq("key"), p.value.eq("value"))
.groupBy(p.value)
.fetchOne();
Adding to #natros answer, Boolean operators can be used for 'and' logic
QResource r = QResource.resource;
QProperty p = QProperty.property;
queryFactory
.select(p.key, p.value.count())
.from(r)
.join(p).on(r.id.eq(p.id))
.where(p.key.eq("key").and(p.value.eq("value")))
.groupBy(p.value)
.fetchOne();
Boolean builders can be also used for complex logics
BooleanBuilder builder = new BooleanBuilder();
builder.and(p.key.eq("key"));
builder.and(p.value.eq("value"));
queryFactory
.select(p.key, p.value.count())
.from(r)
.join(p).on(r.id.eq(p.id))
.where(builder)
.groupBy(p.value)
.fetchOne();
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 new to both Jena-TDB and SPARQL, so it might be a silly question. I am using tdb-0.9.0, on Windows XP.
I am creating the TDB model for my trail_1.rdf file. My understanding here(correct me if I am wrong) is that the following code will read the given rdf file in TDB model and also stores/load (not sure what's the better word) the model in the given directory D:\Project\Store_DB\data1\tdb:
// open TDB dataset
String directory = "D:\\Project\\Store_DB\\data1\\tdb";
Dataset dataset = TDBFactory.createDataset(directory);
Model tdb = dataset.getDefaultModel();
// read the input file
String source = "D:\\Project\\Store_DB\\tmp\\trail_1.rdf";
FileManager.get().readModel( tdb, source);
tdb.close();
dataset.close();
Is this understanding correct?
As per my understanding since now the model is stored at D:\Project\Store_DB\data1\tdb directory, I should be able to run query on it at some later point of time.
So to query the TDB Store at D:\Project\Store_DB\data1\tdb I tried following, but it prints nothing:
String directory = "D:\\Project\\Store_DB\\data1\\tdb" ;
Dataset dataset = TDBFactory.createDataset(directory) ;
Iterator<String> graphNames = dataset.listNames();
while (graphNames.hasNext()) {
String graphName = graphNames.next();
System.out.println(graphName);
}
I also tried this, which also did not print anything:
String directory = "D:\\Project\\Store_DB\\data1\\tdb" ;
Dataset dataset = TDBFactory.createDataset(directory) ;
String sparqlQueryString = "SELECT (count(*) AS ?count) { ?s ?p ?o }" ;
Query query = QueryFactory.create(sparqlQueryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, dataset) ;
ResultSet results = qexec.execSelect() ;
ResultSetFormatter.out(results) ;
What am I doing incorrect? Is there anything wrong with my understanding that I have mentioned above?
For part (i) of your question, yes, your understanding is correct.
For part (ii), the reason that listNames does not return any results is because you have not put your data into a named graph. In particular,
Model tdb = dataset.getDefaultModel();
means that you are storing data into TDB's default graph, i.e. the graph with no name. If you wish listNames to return something, change that line to:
Model tdb = dataset.getNamedGraph( "graph42" );
or something similar. You will, of course, then need to refer to that graph by name when you query the data.
If your goal is simply to test whether or not you have successfully loaded data into the store, try the command line tools bin/tdbdump (Linux) or bat\tdbdump.bat (Windows).
For part (iii), I tried your code on my system, pointing at one of my TDB images, and it works just as one would expect. So: either the TDB image you're using doesn't have any data in it (test with tdbdump), or the code you actually ran was different to the sample above.
The problem in your part 1 code is, I think, you are not committing the data .
Try with this version of your part 1 code:
String directory = "D:\\Project\\Store_DB\\data1\\tdb";
Dataset dataset = TDBFactory.createDataset(directory);
Model tdb = dataset.getDefaultModel();
// read the input file
String source = "D:\\Project\\Store_DB\\tmp\\trail_1.rdf";
FileManager.get().readModel( tdb, source);
dataset.commit();//INCLUDE THIS STAMEMENT
tdb.close();
dataset.close();
and then try with your part 3 code :) ....