I am working with a environment using Hibernate 3.6. I am trying to implement a MySQL table that uses UUIDs from java.util as the PK, these UUIDs are generated from multiple Strings defined by the EntityImage. Here is the code I am using to generate those keys.
public class EntityIDGenerator implements IdentifierGenerator {
...
private UUID generateUUID(String str) {
return UUID.nameUUIDFromBytes(str.getBytes());
}
public UUID generateUUID(EntityImage image) {
return generateUUID(image.getEntityId()+image.getEntityType().toUpperCase()+image.getFilename().toUpperCase());
}
...
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
if(object instanceof EntityImage) {
return generateUUID((EntityImage)object);
}
return null;
}
}
and here his my hibernate
<class name="EntityImage" table="entity_image">
<id name="id" column="id" type="entityUUID" unsaved-value="null">
<generator class="com.covelo.energy.score.db.EntityIDGenerator" />
</id>
<property name="entityId" type="int"/>
<property name="entityType" type="string" length="45" />
<property name="filename" type="string" length="90" />
<property name="fileType" type="string" length="5"/>
<property name="imageData" type="binary" column="image_data"/>
</class>
With my current setup I can only get it to work one way, generate the UUID myself and check if a key exists in the Hibernate then call a save or update accordingly (or just set the UUID to null or the value respectively)
This way seems wrong especially for having this PK generator implemented. Ideally Hibernate would generate a PK using my IdentifierGenerator then check if it exists and update or save it. Am I going about my architecture wrong or is there a method to do this in hibernate?
Note: I am well aware of how saveOrUpdate works Hibernate documentation
-Thanks in advance.
Ned
Related
I'd like to persist LocalDate into Hibernate as a Date type but I can't find it even in the Hibernate documentation. I've tried once but it is stored as blob type.
Here is my Ticket entity:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.clustertech.entity">
<class name="Ticket" table="ticket">
<id name="id" type="int" column="id">
<generator class="native" />
</id>
<property name="date" column="tb_date" type="date" length="35"/>
<property name="topic" column="tb_topic" type="string" length="35"/>
<property name="subject" column="tb_subject" type="string" length="35"/>
<property name="status" column="tb_status" type="string" length="35"/>
<property name="message" column="tb_message" type="string" length="255"/>
<many-to-one name="person" column="person_id"/>
</class>
</hibernate-mapping>
And here is my class entity:
public class Ticket implements Comparable<Ticket> {
private int id;
private LocalDate date;
private String topic;
private String Subject;
private String message;
private String status;
private Person person;
}
It has getters and setters as a normal POJO class. I have seen in other websites one way to do that but they are using anotations. I would like something similar but I am not using anotations just normal POJO class and hbm.xml files. I'm pretty sure I have to create another class in order to convert LocalDate into Date but I don't know how to connect that class with my entity.
You have to create a converter:
#Converter
public class MyConverter implements AttributeConverter<LocalDate, Date> {
#Override
public Date convertToDatabaseColumn(LocalDate localDate) {
if(localDate == null){
return null;
}
return Date.valueOf(localDate);
}
#Override
public LocalDate convertToEntityAttribute(Date date) {
if(date == null){
return null;
}
return date.toLocalDate();
}
}
Then in your hbm.xml file you add you converter as a type of that property:
<property name="date" column="tb_date" type="date"/>
<convert converter="com.mypkg.MyConverter" attribute-name="date"/>
Try this:
<property name="date" column="tb_date" type="LocalDate" />
See Table 2 Java 8 Basic Types from hibernate 5.2 user guide.
(I'm not a native English speaker)
I use Hibernate 5.4, and I found an answer to this problem, which is way easier.
You just have to change the type of your property to org.hibernate.type.LocalDateType.
This works also for LocalDateTime, you just need to change the type to org.hibernate.type.LocalDateTimeType.
For any other type, you should consider looking in org.hibernate.type.
Although the post is very old, but still replying if someone is trying to use LocalDate with hibernate in hbm. In order to use the convertor written by #Maciej Kowalski, one should use the following entry in the hbm file as pointed in hibernate docs Example 28. HBM mapping for AttributeConverter "To map the MoneyConverter using HBM configuration files you need to use the converted:: prefix in the type attribute of the property element."
<property name="birthDate" column="birth_date"
type="converted::com.mypkg.LocalDateConverter"/>
I am trying to implement a one-to-one Hibernate relationship mapping, and I am new to Hibernate technology. My two entity classes are Employee and Client. Client should have a employeeID column as foreign key in database table; i.e. this client is handled by this employee.
Now there are two JSP pages through which I will submit the details of employee and client. First I will add/submit employee JSP. Then on client JSP page there would be a select box consisting employeeIDs as its value.
I have done my JSP part. But I am doubtful of my one-to-one mapping relationship of client with employee. So I am providing my files of code.
Below is my code :
employee class:
public class RWEmp {
private int id;
private String strName;
private String strContactNum;
private String strDateOfJoining;
private String strDesignation;
public RWEmp(){
}
// getter/setters
}
client class:
public class RWClient {
private int id;
private String strName;
private RWEmp poc_emp; // point of contact employee as employee object
public RWClient(){
}
// getter/setters
}
employee.hbm.xml is straight forward. i.e. no relationship.
But client is having a has a relation with employee object.
client.hbm.xml:
<hibernate-mapping>
<class name="com.rightwave.entities.RWClient" table="client_master">
<id name="id" type="int">
<generator class="increment" />
</id>
<property name="strName" type="string" column="cl_name" />
<many-to-one name="poc_emp" class="com.rightwave.entities.RWEmp" column="poc_emp" unique="true"></many-to-one>
</class>
</hibernate-mapping>
persisting class:
public class PersistEntities {
public void clientPersist() {
Session session=Factory.getSession();
Transaction tr=session.beginTransaction();
RWEmp rwEmp =new RWEmp();
rwEmp.setId(2); // this will come from jsp page <select> value. I am doubtful of this, explained below in question.
RWClient rwClient1=new RWClient("wso2",rwEmp);
session.save(rwClient1);
session.flush();
tr.commit();
session.close();
}
}
Here I am not sure if this blueprint is right or wrong. Can I set the employeeID, which will come from my client jsp page (from in <select> box). I am confused because here I am only setting employeeID, which has to be already existing to be a valid foreign key of client. But there are no checks of validating whether this employeeID is already existing or not. The Employee object will definitely be saved (from employee.jsp) before client object.
Am I doing it right way?
When establishing one-to-one relationship with two entities both are assigned the same primary key. A special foreign identifier generator should be declared on Client table to get the primary key value from Employee table. Add constrained="true" to ensure the Employee exists.
<hibernate-mapping>
<class name="com.rightwave.entities.RWClient" table="client_master">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="foreign">
<param name="property">poc_emp</param>
</generator>
</id>
<one-to-one name="poc_emp" class="com.rightwave.entities.RWEmp"
constrained="true"></one-to-one>
<property name="strName" type="string" column="cl_name" />
</class>
</hibernate-mapping>
I am facing a strange problem and am unable to find a solution. I am trying to load a set of objects in Java using Hibernate from MySQl db.
These is a simplified version of my hibernate mappings and code:
<class name="org.Foo.Class1" table="class_profile" >
<cache usage="read-write"/>
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="amount" column="amount"/>
</class>
<class name="org.Foo.Class2" table="class_profile" >
<cache usage="read-write"/>
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="amount" column="amount"/>
</class>
This is my code to access, the objects:
public List<Class1> loadProfiles(final List<Integer> pIds)
{
return (List<Class1>)getHibernateTemplate().executeFind(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
return session.createQuery("from Class1 il where il.id in (:idList)")
.setParameterList("idList", pIds)
.list();
}
});
}
Now, when I run my code
List<Class1> profiles = fooService.loadProfiles(Arrays.asList(3,4));
I get FOUR objects (instead of 2) in the list profiles - TWO Class1 objects and TWO Class2 objects. Where are the TWO Class2 objects coming from?
When you have inheritance between two entities, Hibernate needs to be able to tell which class a particular database row is supposed to represent. You do this by adding a discriminator class to the table that tells it which class to build to represent the row.
Class2 needs to be declared using a <subclass/> element nested inside Class1 that specifies what value of what column is used to tell them apart.
Detials here: http://docs.jboss.org/hibernate/orm/3.5/reference/en/html/inheritance.html#inheritance-tableperclass
i am trying to load a hibernate object ForumMessage but in it contain another object Users and the Users object is not being loaded.
My ForumMessage Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jan 4, 2011 10:10:29 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.ForumMessage" table="FORUMMESSAGE">
<id name="ForumMessageId" type="long">
<column name="FORUMMESSAGEID" />
<generator class="native" />
</id>
<property name="ForumMessage" type="java.lang.String">
<column name="FORUMMESSAGE" />
</property>
<many-to-one name="User" class="com.BiddingSystem.Models.Users" fetch="join">
<column name="UserId" />
</many-to-one>
<property name="DatePosted" type="java.util.Date">
<column name="DATEPOSTED" />
</property>
<many-to-one name="Topic" class="com.BiddingSystem.Models.ForumTopic" fetch="join">
<column name="TopicId" />
</many-to-one>
</class>
</hibernate-mapping>
and I am using the follwing code:
Session session = gileadHibernateUtil.getSessionFactory().openSession();
SQL="from ForumMessage";
System.out.println(SQL);
Query query=session.createQuery(SQL);
System.out.println(query.list().size());
return new LinkedList <ForumMessage>(query.list());
<many-to-one name="User" class="com.BiddingSystem.Models.Users" fetch="join" lazy="false">
You need to add lazy="false" as well.
You can add lazy="false" to the many-to-one mapping which will load the users when the ForumMessage is loaded. Alternatively you could initialize the users list using Hibernate.initialize(). Just make sure you do this before you close the session.
Session session = gileadHibernateUtil.getSessionFactory().openSession();
string sql = "from ForumMessage";
Query query = session.createQuery(sql);
List results = query.list()
for(ForumMessage message : results)
{
Hibernate.initialize(message.User);
}
return new LinkedList <ForumMessage>(results);
You should only do one of these though if you have a need to. Hibernate by default lazy loads objects to avoid unnecessary calls to the database. For example:
public LinkedList getMessages()
{
//It's assumed the session is opened and closed elsewhere.
string sql = "from ForumMessage";
Query query = session.createQuery(sql);
List results = query.list();
//The overhead of extra calls to the database occur here.
//This would have a similar impact if lazy load is set to false.
for(ForumMessage message : results)
{
Hibernate.initialize(message.User);
}
return new LinkedList <ForumMessage>(results);
}
public void printMessages()
{
LinkedList messages = getMessages();
for(ForumMessage message : messages)
{
System.out.println(message.ForumMessage);
}
}
In the above code sample the overhead is incurred for loading all the Users objects but those objects are never used. If Hibernate's lazy-loading were used then this extra overhead would not be incurred. In the following example the list of users isn't loaded until the list is used. This way calls are not made to the database until the data is actually needed.
public LinkedList getMessages()
{
//It's assumed the session is opened and closed elsewhere.
string sql = "from ForumMessage";
Query query = session.createQuery(sql);
List results = query.list();
return new LinkedList <ForumMessage>(results);
}
public void printMessages()
{
LinkedList messages = getMessages();
for(ForumMessage message : messages)
{
//Hibernate will load the users objects here when they are accessed.
for(Users user : message.User)
{
System.out.println(user);
}
}
}
One point to be careful of when lazy loading is all loading must be done in an active session. If you don't have an active session and you try and access something that has not yet been loaded Hibernate will throw a LazyInitializationException.
In addition, using Hibernate's lazy load functionality complies more with the idea of persistence ignorance where as using Hibernate.initialize() does not.
I am having some trouble with returning a non-empty Set into an object using Hibernate and a custom CompositeUserType key.
I have a set of tables and views (simplified here):
create table lang (lang_id,lang_cd);
create table article (art_id,...);
create table article_lang (art_id, lang_id,title,...);
create view article_lang_vw (select * from article join article_lang on art_id);
create table authors(user_id,...);
create table article_authors(art_id,lang_id,user_id);
And database functions:
create or replace procedure addarticle(title,art_id,lang_id) ...
create or replace procedure updatearticle(title,art_id,lang_id)..
create or replace procedure delarticle(art_id,lang_id)..
create or replace procedure addarticleauthor(user_id,art_id,lang_id)...
create or replace procedure delarticleauthor(user_id,art_id,lang_id)...
So to accomplish this mapping using those functions I had to implement CompositeUserType so now I have Java classes like this:
class ProcedureGenerator implements PostInsertIdentityGenerator ...
class Language { int lang_id }
class ArticleLangPKType implements CompositeUserType { //implemented methods }
class ArticleLangPK { int art_id; Language l; }
class Article { ArticleLangPK id; String title; Set<Author> authors; }
class Author { int user_id; String name; }
I want to have a List or Set of Authors. But cannot figure out how to map this part in the *.hbm.xml files. It currently looks something like this:
<class name="Author" mutable="false">
<id name="user_id"/>
<property name="name"/>
</class>
<class name="Article">
<id name="id" type="ArticleLangPKType">
<column name="art_id"/>
<column name="lang_id"/>
<generator class="ProcedureGenerator"/>
</id>
<property name="title"/>
<set name="authors" table="article_authors">
<key> <!-- <key type="ArticleLangPKType"> -->
<column name="art_id"/>
<column name="lang_id"/>
</key>
<many-to-many class="Author" table="article_authors" unique="true"/>
<!-- addauthor, delauthor sql here some how -->
</set>
<sql-insert callable="true">{call addarticle(?,?,?)}</sql-insert>
<sql-update callable="true">{call updatearticle(?,?,?)}</sql-update>
<sql-delete callable="true">{call adddelete(?,?)}</sql-delete>
</class>
But when I run this session.load(Article.class, pk) on an article I know has authors I get a Set size of zero. Otherwise I have no problems inserting, updating, deleting using Hibernate, but now I am stumped. This seems to me to indicate a problem with my ArticleLangPKType.
Any ideas what to do to complete this? Why is my Set always size 0? How would I save the author using the Article's Set and the SQL procedures as provided? Is Hibernate right for me? Do I need a break to see this clearly?
Thanks in advance!
Nevermind I did need a long break. My ArticleLangPK did not override hashCode and Equals correctly. Now just to figure out how to call those other two stored procedures correctly.