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.
Related
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")
})
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
I have a Picture:
public class Picture implements java.io.Serializable {
private byte[] picEncoded;
private String Name;
//etc
Is it's possible to move byte[] to another class without creating physically separated table in db? Do i need to use some inheritance strategy?
edit
Blob in separate entity:
pojo:
public class PictureBlob implements java.io.Serializable {
private Integer pictureBlobId;
private byte[] blob;
hbm::
<class name="PictureBlob" table="PICTURE">
<id name="pictureBlobId" type="int">
<column length="200" name="PictureID"/>
</id>
<property name="blob" type="byte[]" insert="false" update="false">
<column name="PicEncoded" not-null="false"/>
</property>
</class>
Picture:
hbm::
<one-to-one class="PictureBlob" constrained="true" name="pictureBlob" fetch="select"/>
How do i insert new pictures?
PictureBlob pictureBlob= new PictureBlob();
pictureBlob.setBlob(new byte[]{84,32,22});
Picture p = new Picture();
p.setPictureBlob(pictureBlob);
session.save(p);
inserts record where blob value is null.
Is it's possible to move byte[] to another class without creating
physically separated table in db?
Use component mapping which creates a composition relation between Picture and PictureBlob. Example:
<hibernate-mapping>
<class name="Picture" table="PICTURE">
<id name="pictureId" type="int">
<generator class="native" />
</id>
<component name="pictureBlob " class="PictureBlob" lazy="no-proxy">
<property name="pictureBlobId" column="PictureID" type="int" length="200" />
<property name="blob" type="byte[]" insert="false" update="false"column="PicEncoded"/>
</component>
</class>
</hibernate-mapping>
POJO
public class Picture implements java.io.Serializable {
private int pictureId;
private PictureBlob pictureBlob;
//Setters & Getters
}
public class PictureBlob implements java.io.Serializable {
private int pictureBlobId;
private byte[] blob;
//Setters & Getters
}
Also Note:
Use lazy="true" on , and mappings to enable lazy
loading of individual scalar value-typed properties (a somewhat exotic
case). Requires bytecode instrumentation of compiled persistent
classes for the injection of interception code. Can be overriden in
HQL with FETCH ALL PROPERTIES.
Use lazy="no-proxy" on single-valued associations to enable lazy
fetching without the use of a proxy. Requires bytecode instrumentation
for the injection of interception code.
Use lazy="extra" on collections for "smart" collection behavior, i.e.
some collection operations such as size(), contains(), get(), etc. do
not trigger collection initialization. This is only sensible for very
large collections.
See here for more info. on fetching strategies
Edited.
if you interested in using annotations instead of hbm you can take a look at these
http://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html, this will exactly solve your purpose.
I think you could use something like this:
<class name="Picture">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="pictureBlob" class="PictureBlob">
<property name="pictureBlobId"/>
<property name="blob"/>
<property name="picture"/>
</component>
</class>
This might need some edititng, but the idea is this:
You have a Picture class. This class has property name and property pictureBlob of type PictureBlob.
the component tag indicates the properties inside the component are mapped to the same table as Picture
I have two classes A and B. Many B's can have association with a single A, hence a many-to-one relationship from B to A. I've mapped the relationship like:
<class name="A" table="tbl_A">
<property name="propA" column="colA"/>
</class>
<class name="B" table="tbl_B">
<property name="propB" column="colB"/>
<many-to-one name="a" class="A" column="col1" cascade="delete"/>
</class>
A has nothing mapped to B. Keeping this in mind we intend to delete B when it's associated A is deleted. This could have been possible if I could define an inverse="true" on the many-to-one association in B but hibernate does not allow that.
Can anyone help with this? We do not want to write anything in A for this.
Hibernate only cascades along the defined associations. If A knows nothing about Bs, nothing you do with A will affect Bs.
Pascal's suggestion is, therefore, the easiest way to do what you want:
<class name="A" table="tbl_A">
...
<set name="myBs" inverse="true" cascade="all,delete-orphan">
<key column="col1"/>
<one-to-many class="B"/>
</set>
</class>
<class name="B" table="tbl_B">
...
<many-to-one name="a" class="A" column="col1" not-null="true"/>
</class>
Note that setting cascade="delete" on B as you have it in your original code will NOT do what you want - it tells Hibernate to "delete A if B is deleted" which is likely to result in constraint violation (if there are any other Bs linked to that A).
If you absolutely cannot add a collection of Bs to A (though I can't really think of the circumstances where that'd be the case), your only other alternative is to define cascade delete from A to B at the foreign key level; your Bs will then be deleted when your A is deleted.
This is a rather ugly solution, however, because you have to be extremely careful of how you delete A in Hibernate:
Session must be flushed prior to deleting A (having pending updates to B may result in an error or A and some Bs being re-inserted behind the scenes)
All Bs linked to your A (and since you're not maintaining the relationship from A side that means all Bs) must be evicted from all active sessions and 2nd level cache.
I think you need to cascade="all,delete-orphan" from A to B's with a one-to-many association.