Hibernate - One table with multiple entities? - java

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

Related

How do I implement idbag with element in annotations?

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.

Econtainer null when loading EMF containment from Database using Hibernate

I have an EMF containment hierarchy: An House contains a list of Rooms, represented using an ecore file.
Before persisting, when I initially create my house and populate it with rooms, the eContainer value for a Room object correctly show the containing house. I then use Hibernate (no Teneo involved) to save the house (which cascade-saves the rooms).
When I reload the House object, I get references to all the Rooms. However, the eContainer value for a Room is now null. This is relevant because I use EcoreUtil.delete(bathroom) to delete a Room from its containing house, and that uses EObject.eContainer().
Relevant Hibernate Mapping:
<class name="House" table="house" lazy="false">
<bag name="rooms" lazy="true" cascade="save-update, delete">
<key update="true">
<column name="house_id" unique="false"/>
</key>
<one-to-many class="Room"/>
</bag>
</class>
<class name="Room" table="room" lazy="false">
</class>
What should I do to delete EMF objects? Should I call something other than EcoreUtil.delete(obj)? Should I manually add the eContainer references on load? Should I change my hibernate mapping?
Hibernate requires every property to have a getter and setter. In EMF (not using Teneo at least), there is a getter for Rooms but no setter.
public EList<Room> getRooms() {
if (rooms == null) {
rooms = new EObjectContainmentEList<Room>(Room.class, this, housePackage.HOUSE__ROOM);
}
return rooms;
}
I provided my own setter below.
public void setRooms(List<Room> roomList) {
this.rooms = new BasicEList<>();
this.rooms.addAll(roomList);
}
This was incorrect because a BasicEList does not do any provide EMF notification, so the eContainer was not getting set. I changed to the following, which in the underlying implementation uses a EObjectContainmentEList and so far it seems to work.
public void setRooms(List<Room> roomList) {
ECollections.setEList(getRooms(), roomList);
}

Hibernate unsaved-value annotation

I would like to force Hibernate (4.2) checking object persistence by the field VERSION instead of the field ID. The xml below should work:
<id name="id" column="ID">
<generator class="assigned" />
</id>
<version name="version" column="VERSION" unsaved-value="null" />
But I want to use annotations. Is this java code enough?
#Id
public String getId() {
return this.id;
}
#Version
public Integer getVersion() {
return this.version;
}
How to specify the unsaved-value tag? I don't find any annotation for this.
I've read somewhere, that Hibernate is smart enough to guess that an object is persistent or not, but it was not too convincing.
And what if I want to use -1 instead of null? There must be a way to achieve this, isn't it?
<version name="version" column="VERSION" unsaved-value="negative" />
Thanks for your help.
Edited. Hibernate 3.6 ref guide says:
"The unsaved-value attribute is almost never needed in Hibernate3 and indeed has no corresponding element in annotations."
and
"The assigned generator makes Hibernate use unsaved-value="undefined". This forces Hibernate to go to the database to determine if an instance is transient or detached, unless there is a version or timestamp property, or you define Interceptor.isUnsaved()."
I belive #Version will be sufficient for me.

Java DataType mismatch between Oracle and hibernate

My java application is using hibernate with Oracle 10g as the database.
I have landed into an issue and not able to proceed and i need your help here.
Below is the issue that i am facing.
I have a Column in one of my Oracle table which has a datatype of Varchar2(1 byte).
I want to know the proper dataype that i need to use in my pojo class.
Also in the hibernate mapping file what should be the datatype for the same property.
when i am running the file hibernate keeps on giving error like cannot do a conversion.
below are my pojo and .hbm file
public class destination implements Serializable{
private String configId;
private String isCurrent;
//other properties and getter, setters
}
destination.hbm.xml
<class name="com.testing" table="configuration">
<id name="configID" type="java.lang.Integer">
<column name="configuration_id" />
<generator class="identity" />
</id>
<property name="isCurrent" type="Not-SURE">
<column name="is_current" not-null="true" />
</property>
The column i am talking about is the isCurrent property in the pojo and .hbm.xml file.
Its defined as Varchar2(1 byte) in the db. I ma not sure about the datatype and marked it a String but the issue still persists.
I have searched the net but have not got any proper solution for this issue.
Can you please help me here as its really eating my head a lot.
I would focus on the configId you declared it as String in the class but as Integer in the xml.
<id name="configID" type="java.lang.Integer">
Im guessing you want to store current flag on the record. In that case you can do
public class destination implements Serializable{
private String configId;
private boolean current;
public boolean isCurrent() {
return current;
}
}
and hbm mapping like
<property name="current" type="yes_no">
<column name="is_current" not-null="true" />
</property>

Beginners Hibernate problem - simple mapping with non-simple exception!

Please help me with this hibernate problem, I'm new to hibernate and still trying to get my head around it. I can't seem to work this issue out. I imagine I'm missing something pretty simple.
I've followed the example here to achieve a many-to-one mapping, as my requirements are almost identical: http://www.coderanch.com/t/217519/ORM/java/Hibernate-Newbie-Many-Relation-Tutorial
Please note that when I try to persist the Picture object, the user variable is (at that point in time) empty, as is every other variable bar image.
Also note that I've set hibernate to generate the database schema by itself via config in the hibernate config file.
Here are my mapping files (declarations removed)
User.hbm.xml
<class name="msc.model.User" table="USER">
<id name="id" column="USER_ID">
<generator class="native"/>
</id>
<property name="username"/>
<property name="email"/>
<bag name="pictures"
table="PICTURE"
lazy="true"
cascade="save-update">
<key column="PICTURE_ID"/>
<one-to-many class="msc.model.Picture" />
</bag>
</class>
And Picture.hbm.xml
<class name="msc.model.Picture" table="PICTURE">
<id name="id" column="PICTURE_ID">
<generator class="native"/>
</id>
<property name="story"/>
<property name="tattooist"/>
<property name="pic"/>
<many-to-one name="user"
class="msc.model.User"
column="USER" />
<property name="image" type="blob">
<column name="IMAGE" not-null="true" />
</property>
</class>
The class files (getters and setters stripped)
Picture.java
package msc.model;
import java.io.File;
import java.sql.Blob;
public class Picture {
private Long id = null;
private User user = null;
private File pic = null;
private String story = null;
private String tattooist = null;
private Blob image = null;
}
User.java
package msc.model;
import java.util.ArrayList;
import java.util.List;
public class User {
private Long id = null;
private String username = null;
private String email = null;
private List<Picture> pictures = null;
}
The persistence code (note that bFile is byte stream created from a file):
Session hib_ses = HibernateUtil.getSessionFactory().getCurrentSession();
hib_ses.beginTransaction();
Picture picture = new Picture();
picture.setImage(Hibernate.createBlob(bFile));
Long id = (Long) hib_ses.save(picture);
hib_ses.getTransaction().commit();
Here is the exception:
Cannot add or update a child row: a foreign key constraint fails (`msc`.`picture`, CONSTRAINT `FK85BE8DE2885129D` FOREIGN KEY (`PICTURE_ID`) REFERENCES `user` (`USER_ID`))
Please help!
There is something very strange going on if that is the real error you get.
Cannot add or update a child row: a foreign key constraint fails (`msc`.`picture`, CONSTRAINT `FK85BE8DE2885129D` FOREIGN KEY (`PICTURE_ID`) REFERENCES `user` (`USER_ID`))
This says that PICTURE.PICTURE_ID is a reference to USER.USER_ID. But PICTURE_ID is the PK of picture, which Hibernate will generate upon insertion. Did you mean to create a constraint from PICTURE.USER to USER.USER_ID?
Oh, I see you wrote you generate the schema via Hibernate. I think the error is in your "bag" definition. The key column should not be PICTURE_ID, but USER.
It looks like you are trying to save the Picture before saving the User. Try saving the User first.
[edit]
From the mapping - it looks like there is a Parent/Child relationship between User and Picture.
There is a good example in the Hibernate Documentation for a Parent Child relationship.
If you want the User to be able to be null, then a uni-directional relationship would be better.
[edit]
Another good reference about mapping collections with Hibernate.

Categories