Hey guys,
I have a few questions regarding HQL. I have following entities:
@Entity
public class MyObject {
@Id
private String id;
@Embedded
private PolyString name;
...
}
@Embeddable
public class PolyString {
private String orig;
private String norm;
...
}
This code has to run on top of h2, mysql, mariadb, oracle, postgresql, sqlserver - so I’m happy to use hibernate, dialects and so on. I’m using Hibernate 5.2.2.Final.
Question 1:
I’ve tried to write HQL to update my objects like this:
Query query = session.createQuery("update MyObject o set o.name = :name where o.id = :id");
query.setParameter("name", new PolyString("a", "a"));
query.setParameter("id", "123");
query.executeUpdate();
This query will fail, as it’s not able to handle that embedded entity correctly - exception:
Caused by: org.hibernate.QueryException: assignment in set-clause not associated with equals [update com.example.MyObject o set o.name = :name where o.id = :id]
at org.hibernate.QueryException.generateQueryException(QueryException.java:120)
at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:218)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
Caused by: org.hibernate.QueryException: assignment in set-clause not associated with equals
at org.hibernate.hql.internal.ast.tree.AssignmentSpecification.<init>(AssignmentSpecification.java:43)
at org.hibernate.hql.internal.ast.HqlSqlWalker.evaluateAssignment(HqlSqlWalker.java:1278)
at org.hibernate.hql.internal.ast.HqlSqlWalker.evaluateAssignment(HqlSqlWalker.java:1272)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.assignment(HqlSqlBaseWalker.java:1063)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.setClause(HqlSqlBaseWalker.java:763)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:379)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:267)
Am I doing something wrong? I know I can do set o.name.orig = :orig, o.name.norm = :norm
but that looks kinda stupid. I thought that hibernate will know what to do.
Question 2:
If if overcome previous issue, then this query doesn’t generate only SQL update but it will create temp table, insert ids using select based on where clause from update, then does update using this temp table and at last it drops temp table. Now the question is - if I know that that HQL update has to update only 1 row (or maybe just a few rows) how can I disable that temp table magic, but just for this query, not globaly?
I expect that MultiTableBulkIdStrategy handles all temp table stuff. Is it possible to send some query hints there? I can’t create custom implementation as for different DB vendors hibernate uses different multitable strategies so I would have to reimplement almost all of them. Even if id did. I couldn’t find a place where I would be able to read some query hint or something passed from that query code.
Question 3:
Dialect.supportsTemporaryTables();
Dialect.generateTemporaryTableName();
Dialect.dropTemporaryTableAfterUse();
Dialect.getDropTemporaryTableString();
These methods disapeared from Dialect class, MultiTableBulkIdStrategy was introduced. If I want to do some custom SQL and I need temp tables - is it possible to get that SQL “parts” somewhere? For now I overcomed this with nasty hack - I’ve created class hierarchy TempTableDialect and copied there implementations for these methods from other dialects. I don’t like it but I don’t know how to handle it. No docs for it either.
Bigger picture
I’m trying to implement relative changes processing on top of hibernate. I want to get rid of session.merge() calls. It causes a lot of selects to fetch detached instances and then also unnecessary updates/deletes. I do understand that it’s necessary to have robust algorithm. In our case we do get relative change description even at repository layer like:
- add some reference to XY
- update givenName to “abc”
So that we know we want to insert row here or delete row there, update some column and so on.
@sebersole you’re mentioned as an author all around that multitable code, maybe you can help a bit?
Thank you very much.