I am migrating an application running with Hibernate 3 to Hibernate 5.
I have a strange error:
ERROR: relation hibernate_sequence does not exist
We are using *.hbm.xml mapping files and everything was working fine until I changed the Hibernate version. I mean we have a pretty straight forward mapping with ID column and DB sequence generator and still Hibernate wasn't able to pick the correct config.
<hibernate-mapping>
<class name="com.boyan.MyClass" table="my_class">
<id name="id" type="long">
<column name="id" />
<generator class="sequence">
<param name="sequence">my_class_seq</param>
</generator>
</id>
...
</class>
</hibernate-mapping>
I started digging in the Hibernate code and saw that SequenceGenerator is deprecated and the new versions use SequenceStyleGenerator. I was very confused when I noticed that in the new version the property telling which is the sequence name is changed from sequence to sequence_name. So finally when I changed:
<param name="sequence">my_class_seq</param>
to:
<param name="sequence_name">my_class_seq</param>
everything worked.
I bumped in to the same problem and I was using annotations. Solution was the accepted answer JPA GenerationType.AUTO not considering column with auto increment. If using annotations following should be used.
#GenericGenerator(name = "my_seq", strategy = "native", parameters = {
#Parameter(name = "sequence_name", value = "mydb_seq")
})
Related
We use Spring + Hibernate for a Webapp.
This Webapp will be deployed on two unrelated production sites. These two production sites will use the Webapp to generate and use Person data in parallel.
What I need to do, is to make sure that the Persons generated on these two unrelated production sites all have distinct PKs, so that we can merge the Person data from these two sites at any time.
A further constraint imposed to me is that these PKs fit in a Long, so I can't use UUIDs.
What I'm trying to do is to change the current hibernate mapping, that has sequence S_PERSON as generator:
<hibernate-mapping default-cascade="save-update" auto-import="false">
<class name="com.some.domain.Person" abstract="true">
<id name="id">
<column name="PERSON_ID"/>
<generator class="sequence">
<param name="sequence">S_PERSON</param>
</generator>
</id>
...
</hibernate-mapping>
into something configurable, so that PERSON_ID have its PKs generated from different sequences (maybe S_PERSON_1 and S_PERSON_2) depending on the deployment site's Spring configuration files.
Of course,
<generator class="sequence">
<param name="sequence">${sequenceName}</param>
</generator>
doesn't work, so I have to figure out something else... I guess my generator should point to a configurable bean that in turn points to a sequence or another, but I can't figure how to do that...
Any ideas or workaround?
You could use sequences on both production systems, but define them differently:
Production System 1:
CREATE SEQUENCE sequence_name START WITH 1 INCREMENT BY 2;
Production System 2:
CREATE SEQUENCE sequence_name START WITH 2 INCREMENT BY 2;
The first sequence will generate only odd numbers, the second only even numbers.
I'm working on a refactor where I have to change my classes from hibernate xml to annotations (JPA annotations preferred but hibernate okay). One of my entities uses the hibernate idbag feature combined with the element feature and a join table.
hibernate xml:
<class name="com.my.package.EntityA" table="table_a">
<id name="id" column="table_a_id" type="long" unsaved-value="null">
<generator class="sequence">
<param name="sequence">table_a_seq</param>
</generator>
</id>
<idbag name="entityBIds" table="table_a_b" cascade="all" lazy="false">
<collection-id column="table_a_b_id" type="long">
<generator class="org.hibernate.id.SequenceGenerator">
<param name="sequence">table_a_b_seq</param>
</generator>
</collection-id>
<key column="fk_table_a_id" />
<element column="fk_table_b_id" type="long"/>
</idbag>
</class>
The class looks like this:
public class EntityA {
Long id;
Collection<Long> entityBIds;
}
Schema:
table_a
table_a_id number(13,0)
table_b
table_b_id number(13,0)
table_a_b
table_a_b_id number(13,0)
fk_table_a_id number(13,0)
fk_table_b_id number(13,0)
How would I use annotations to implement this? Note that this is a pretty complex system and I want to minimize the changes that I have to make aside from the annotations.
What you want is a one-to-many relation with a join table.
See https://en.wikibooks.org/wiki/Java_Persistence/OneToMany ยง1.5 Join Table
Your table model is not practical with both tables table_a and table_a_b. But changing it would be costly I guess.
I hope your java model is more flexible...
Define an EntityB with only a Long id. In EntityA have a Collection<EntityB> entityBs and adapt the implementation of your getEntityBIds / setEntityBIds / addEntityBId / etc. to access it and convert as required. Of course hoping the field entityBIds was private and thus not used outside the entity.
I discovered the answer!
#ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER)
#CollectionTable(name = "TABLE_A_B", joinColumns = #JoinColumn(name="fk_table_b_id"))
#Column(name = "fk_table_a_id")
private Collection<Long> entityBIds;
Of course doing this is less than elegant, but I needed the simplest way to convert to annotations without breaking the complex code surrounding the entities.
I encounter strange behaviour on Hibernate's merge() if I use an entity with a composite-id and a version number.
This is my hibernate mapping file:
<class name="ArticleTurnover" table="T_ARTICLETURNOVER">
<composite-id>
<key-property name="mainArticleId" type="java.lang.Integer" column="ARTICLETURNOVER_ID"/>
<key-property name="locationId" type="java.lang.Integer" column="ARTICLETURNOVER_LOCATIONID"/>
</composite-id>
<version name="version" column="ARTICLETURNOVER_VERSION" />
... some properties
</class>
And this is the code (it fails...):
ArticleTurnover at = new ArticleTurnover();
at.setMainArticleId(1);
at.setLocationId(1);
ArticleTurnover savedAt = em.merge(at);
assertNotNull(savedAt.getMainArticleId());
assertNotNull(savedAt.getLocationId());
After calling merge the fields mainArticleId and locationId are both null. The code above is just a test, but if I would commit a transaction, hibernate would insert null into the composite-id fields, and fail!
If I change em.merge(at) to em.persist(at) everything works. And if I manually set at.setVersion(0) (!!) it also works.
I ended up in adding a component type ArticleTurnoverId for my composite-id like mentioned here: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e4819.
Can anybody tell me what I am doing wrong, or point out why this happens?
I use hibernate to generate ids for my MySQL data-tables:
<class name="XXXX" table="XXXX">
<id name="Id" column="Id" type="string">
<generator class="guid"/>
</id>
....
</class>
it works fine.
however, when i profiling the sql queried, there are 2 sqls for 1 insert:
1).select uuid() and then 2).insert ....
I have 3 questions:
why not hibernate generates the "GUID"s locally?
how much is the overhead for "select uuid()" than "UUID.randomUUID()" for one insert?
can i config a "local" generator in hibernate?
AFAIK the GUID generator is deprecated and you should use the new(er) UUIDGenerator instead. See http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e5294.
But to answer your questions
That is how the GUID generator functions it calls the database and the result is passed into the id field of the object
No idea, measure, however I guess the impact is negligible as the only thing you do additionally is return a simply value
Yes but why as it is already supported by Hibernate (see the documentation)
I've to switch persistence of a project using HIBERNATE to OPENJPA and I started from entities and hbm files which define type of columns, etc.
I've an Id on hibernate generated in this way:
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="sequence">
<param name="sequence">seq_illness</param>
</generator>
</id>
how can I "translate" it ointo Jpa annotation to my entity class, in particular how can I represent sequence generator?
I'm new to this feature and I don't understand well usage of
#GeneratedValue(strategy = GenerationType.SEQUENCE)
how can I reproduce sequence parameter and define the correct sequence generator?
In JPA, the mapping for this column would look like:
#Id
#SequenceGenerator(name="ID_GEN" sequenceName="NAME_OF_SEQ_IN_DB")
#GeneratedValue(generator="ID_GEN")
private Integer id;
See the following documentation for further information:
#SequenceGenerator
#GeneratedValue