I recently had a similar issue as this SOer had, where I was using Hibernate's Query#list object and getting compiler warnings for type safety.
Someone pointed out to me that I could use EntityManager#createQuery(String,Class<?>) instead of Query#list to accomplish the same thing but have everything genericized correctly.
I've been searching for examples of using Hibernate directly with EntityManager but so far no luck. So I ask: how can I use the EntityManager#createQuery method in lieu of the Query#list method when doing a SELECT from Hibernate?
Related
Synopsis: I'm trying to create an SQL update using jOOQ
DSL.using(connection)
.update(DSL.table("dogs"))
.set(DSL.field("age"), DSL.field("age").add(1))
.set(DSL.field("rabies"), "true")
.where(DSL.field("id").eq("Kujo"))
.execute();
Issue:
The method set(Field<Object>, Object) is ambiguous for the type UpdateSetFirstStep<Record>
Question: How do I create this update using jOOQ?
You ran into this problem: Reference is ambiguous with generics
Fixing your query
It's always a good idea to attach data types with your jOOQ expressions. In your particular case, you can work around the problem by specifying things like:
DSL.field("age", SQLDataType.INTEGER)
Or, shorter, with the usual static imports:
field("age", INTEGER)
Using the code generator
However, jOOQ is best used with its code generator, see also this article here. Not only will you avoid problems like these, but you also get compile time type safety (of data types and meta data), advanced features like implicit joins and much more.
Your query would then look like this:
DSL.using(connection)
.update(DOGS)
.set(DOGS.AGE, DOGS.AGE.add(1))
.set(DOGS.RABIES, true)
.where(DOGS.ID.eq("Kujo"))
.execute();
I'm currently evaluating JOOQ because I believe I started reinventing the wheel which looks very close to part of JOOQ :)
Now, while digging in great JOOQ documentation I've found that my use case lies somewhere between Using JOOQ as SQL Builder and Using JOOQ as SQL Builder with Code generation i.e. I would like to:
Create plain SQL strings like it is shown in Using JOOQ as SQL Builder part
Instead of using hard-coded DSL.fieldByName("BOOK","TITLE") constructs, I prefer storing name of a table along with it's column names and types like it's shown in Using JOOQ as SQL Builder with Code generation part
I prefer not to use code generation (at least not on regular basis), but rather creating TableImpl myself when new table is needed.
While digging in manual, I've found how table implementation should look like in chapter Generated tables. However, TableImpl class as well as Table interface should be parameterized with record type and the same goes for TableField class. I believe this is done for easier type inference when directly querying database and retrieving results, though I may be mistaken.
So my questions are:
Is there a guide in manual on how to create Table and TableField implementations? Or I can simply generate them once for my database schema and use generated code as a guideline?
How can I gracefully "discard" record type parameters in implemented classes? First, I thought about using java.lang.Void class as type parameter but then I noticed that only subclasses of Record are allowed... The reason is that I don't need record types at all because I plan to use generated by JOOQ SQL queries in something like Spring JdbcTemplate so mapping is done by myself.
Thanks in advance for any help!
Given your use-case, I'm not sure why you'd like to roll your own Table and TableField implementations rather than using the ones generated by jOOQ. As you stated yourself, you don't have to regenerate that code every time the DB schema changes. Many users will just generate the schema once in a while and then put the generated artefacts under version control. This will help you keep track of newly added changes.
To answer your questions:
Yes, there are some examples around the use of CustomTable. You may also find some people sharing similar experiences on the user group
Yes you can just use Record. Your minimal custom table type would then be:
class X extends TableImpl<Record> {
public X() {
super("x");
}
}
Note that you will be using jOOQ's internal API (TableImpl), which is not officially supported. While I'm positive that it'll work, it might break in the future, e.g. as the super constructor signature might change.
I am using Hibernate for a few years but am not sure about the usage of Query and Criteria.
I understood, that one of Hibernate strengths are to control the field name in one place.
If I have the following code:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
What if I change "name" of the Cat in the java object?
Even when using refactor replace (like in Elipse) it will not detect the element as something that needs to be changed!
If so , how do you maintain the field names in Java?
I believe type safe queries are not supported in Hibernate specific api. JPA 2 however has support for it. Read this: Dynamic, typesafe queries in JPA 2.0
I've got the same problem in the past, and actually there's no way to have a typed and refactor resistant(change name) reference of a field in java, so is neither possible have a query builder that allow this, but i tried to build a implementation of a query builder that using some workaround try to allow you to write type safe and refactor resistant query, it's name is ObjectQuery and you can found some information about here.
let me know if it solve your use case !
obviously is nothing of standard so if you are looking to something of standard, is better JPA Typesafe but it not have the same power!
I am trying to define xml mapping for a Map<String,String> field.
The entity class cannot be modified so I am using the XML variant of JPA mapping, but cannot figure out the proper syntax.
Can someone explain how to write the JPA xml for this case - or explicitly state that this is impossible with xml but possible with annotations as mentioned in Storing a Map<String,String> using JPA ...
I will even appreciate to know that this is impossible - ideally when it comes with reference to the part of specification that states it.
These primitive relations have been added in JPA2 so you have to use a JPA2 imeplementation. I use Eclipselink. The keyword is "ElementCollection". It seems this has allready been discussed here:
Storing a Map<String,String> using JPA
After more time and searching for different things I happened to find the answer here:
http://wiki.eclipse.org/EclipseLink/Development/JPA_2.0/new_collection_mappings#XML_2
The solution is:
<element-collection name="quotes">
<column name="QUOTE"/>
<map-key-column name="Q_DATE"/>
<collection-table name="EBC_QUOTES">
<join-column name="EBC_ID"/>
</collection-table>
</element-collection>
You haven't specified which JPA implementation you're using, but I think this should work for both OpenJPA and Hibernate... See here:
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Example_of_a_map_key_column_relationship_XML
The difficulty you'll run into is that you're mapping to a primitive type instead of an entity type. I won't say it's impossible, but I will say from experience that it's painful.
It looks like that Hibernate started using LONG data type in version 3.5.5 (we upgraded from 3.2.7) instead of CLOB for the property of type="text".
This is causing problems as LONG data type in Oracle is an old outdated data type (see http://www.orafaq.com/wiki/LONG) that shouldn’t be used, and tables can’t have more than one column having LONG as a data type.
Does anyone know why this has been changed?
I have tried to set the Oracle SetBigStringTryClob property to true (as suggested in Hibernate > CLOB > Oracle :(), but that does not affect the data type mapping but only data transfer internals which are irrelevant to my case.
One possible fix for this is to override the org.hibernate.dialect.Oracle9iDialect:
public class Oracle9iDialectFix extends Oracle9iDialect {
public Oracle9iDialectFix() {
super();
registerColumnType(Types.LONGVARCHAR, "clob");
registerColumnType(Types.LONGNVARCHAR, "clob");
}
}
However this is the last resort - overriding this class is step closer to forking Hibernate which I would rather avoid doing.
Can anybody explain why this was done?
Should this be raised as a bug?
[UPDATE]: I have created https://hibernate.atlassian.net/browse/HHH-5569, let's see what happens.
It looks like the resolution to this issue is to use materialized_clob, at least that's what's being said by Gail Badner on HHH-5569.
This doesn't help me at all (and I left relevant comment about that) but might be helpful for someone else here. Anyway the bug is rejected and there is very little I can do about it but use overriden dialect :(
Can anybody explain why this was done? Should this be raised as a bug?
This has been done for HHH-3892 - Improve support for mapping SQL LONGVARCHAR and CLOB to Java String, SQL LONGVARBINARY and BLOB to Java byte[] (update of the documentation is tracked by HHH-4878).
And according to the same issue, the old behavior was wrong.
(NOTE: currently, org.hibernate.type.TextType incorrectly maps "text" to java.sql.Types.CLOB; this will be fixed by this issue and updated in database dialects)
You can always raise an issue but in short, my understanding is that you should use type="clob" if you want to get the property mapped to a CLOB.
PS: Providing your own Dialect and declaring it in your Hibernate configuration (which has nothing to do with a fork) is IMHO not a solution on the long term.
I cannot answer your question about why, but for Hibernate 6, it seems they're considering switching back to using CLOB