How to write update Query in CriteriaUpdate using joins? - java

I trying to write code regarding CriteriaUpdate using joins.
but, in CriteriaUpdate joins are not working.
Then I tried using subqueries like below ..,
CriteriaBuilder userBuilder = deviceSession.getCriteriaBuilder();
CriteriaUpdate<Switch> deviceUpdate = userBuilder.createCriteriaUpdate(Switch.class);
Root<Switch> deviceUpdateRoot = deviceUpdate.from(Switch.class);
Subquery<Switch> deviceSubquery = deviceUpdate.subquery(Switch.class);
Root<Switch> roomRoot = deviceSubquery.from(Switch.class);
Join<Switch, Rooms> join = roomRoot.join("room" ,JoinType.LEFT);
deviceUpdate.set(deviceUpdateRoot.get("displayName"),"SSS");
deviceUpdate.set(deviceUpdateRoot.get("device"),"device");
deviceUpdate.set(deviceUpdateRoot.get("operation"),"operation");
***deviceUpdate.set(join.get("roomId"),device.getRoomId());***
deviceUpdate.where(userBuilder.equal(deviceUpdateRoot.get("deviceName"),device.getDeviceName()));
int returnValue = deviceSession.createQuery(deviceUpdate).executeUpdate();
but I am getting error like org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'generatedAlias1.roomId'
can you please help from this isuue.

Related

Wrong result metadata when using pagination with Balze-Persistence

When I fetch all results without pagination result is OK but when use pagination appear problem in pagination metadata
Page p=PageImpl(result.getResults(), PageRequest.of(pageNo, pageSize), result.getTotal())
p.getTotalElements() // wrong result
p.result.getTotalPages() // also is wrong
code snippet:-
QOrderAppliedTax qTax = QOrderAppliedTax.orderAppliedTax;
QOrderDetails qOrderDetails = QOrderDetails.orderDetails;
NumberExpression<Integer> groupBy = qOrderDetails.createdDate.yearWeek();
StringPath name = qTax.name;
NumberExpression<Double> totalTaxValue = qTax.value.sum();
NumberExpression<Long> ordersCount = qOrderDetails.order.countDistinct();
DateTimeExpression<Date> fromDate = qOrderDetails.createdDate.min();
DateTimeExpression<Date> toDate = qOrderDetails.createdDate.max();
CriteriaBuilderFactory cbf = Criteria.getDefault().createCriteriaBuilderFactory(entityManagerFactory);
QueryResults<TaxDto> result= new BlazeJPAQuery<>(em, cbf)
.select(Projections.constructor(TaxDto.class, fromDate, toDate, groupBy, name, totalTaxValue,
ordersCount))
.from(qTax).innerJoin(qOrderDetails).on(qTax.orderDetails.eq(qOrderDetails))
.groupBy(taxName, groupBy).offset(pageNo * pageSize).limit(pageSize).fetchResults();
the wrong result appears even I used
orderBy(groupBy.asc(), taxName.asc())
exactly the two fields in order by is unique together.
This issue turned out to be a bug which will be resolved in Blaze-Persistence 1.6.3 (expected soon). The patch has already landed in 1.6.3-SNAPSHOT.

Querydsl: How to write a "complex" query

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();

jOOQ how to use optional sorting

I have a query which selects persons from a table.
SelectConditionStep<PersonRecord> select = context
.selectFrom(Tables.PERSON)
.where(Tables.PERSON.ISDELETED.eq(false));
if(searchValue != null && searchValue.length() > 0){
select.and(Tables.PERSON.LASTNAME.likeIgnoreCase(String.format("%%%s%%", searchValue)));
}
List<PersonRecord> dbPersons = select
.orderBy(Tables.PERSON.LASTNAME, Tables.PERSON.FIRSTNAME, Tables.PERSON.ID)
.limit(length).offset(start)
.fetch();
This code works pretty well. Because I display the data in a datatables table I need to have optional / dynamic sorting capability. I did not find a solution so far.
found the solution myself now:
Collection<SortField<?>> sortFields = new ArrayList<>();
sortFields.add(Tables.PERSON.FIRSTNAME.asc());
List<PersonRecord> dbPersons = select
.orderBy(sortFields)
.limit(length).offset(start)
.fetch();

How to set a property path in Jena's Sparql API?

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"));

How to get fully materialized query from querydsl

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!

Categories

Resources