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.
Related
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'm working with Hibernate 4.3.5, Java 1.6 and Spring 4.0.3.
I've mapped the entities through hbm, and I want my application works with logical deletion.
So, in each mapped entity, I've added a property named 'deleted', which indicates if an entity is deleted or not.
Because I don't want to load the deleted entities (the ones having true the deleted property), I've used the where clause in the mapped classes, so I only get the entities aren't logically deleted.
And also, I've added the same where clause to every one-to-many relationship.
In one particular case, I've got a Report entity that has a one-to-many relationship with the Document entity.
So, when I mark a Document as deleted, and I save the Report entity (with merge), I expect than the Report entity doesn't keep the Document marked as deleted. But this doesn't occur.
This is the hbm for the Report entity:
<hibernate-mapping>
<class
name="es.entities.Report"
table="reports"
dynamic-insert="false"
dynamic-update="false"
where="deleted = 0">
<id name="id">
<generator class="identity"/>
</id>
<property name="title"></property>
<property name="deleted"></property>
<set
name="documents"
table="documents"
cascade="all"
lazy="false"
where="deleted=0">
<key column="id_report"/>
<one-to-many class="es.entities.Document"/>
</set>
</class>
</hibernate-mapping>
Here it is the hbm for the Document entity:
<hibernate-mapping>
<class
name="es.entities.Document"
table="documents"
dynamic-insert="false"
dynamic-update="false"
where="deleted = 0">
<id name="id">
<generator class="identity"/>
</id>
<property name="name"></property>
<property name="type"></property>
<property name="size"></property>
<property name="deleted"></property>
</class>
</hibernate-mapping>
I use a Service (ReportService) to open a Spring transaction. The method is:
#Autowired
private ReportDao reportDao;
#Transactional
public Report save(Report report) {
this.reportDao.save(report);
}
And this is the DAO (ReportDao) method I use to save the Report entity:
public Report save(Report report) {
return (Report) this.currentSession().merge(report);
}
I put an example:
The parameter I send to the service contains a Report object, with two Document objects, one of them deleted and the other not.
The DAO method returns the same information, but I'd like this method returns only the documents are not deleted.
Note: if I use another method with another transaction, I obtain the report only with the document is not deleted, but I'd like to do this in the same transaction.
Can anybody help me or show me an alternate to this? It is possible to use other Session method than merge?
Thanks a lot.
Merge method create a copy from the passed entity object and return it. Try re-fetching the report entity post merge.
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
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 getting the following exception while adding data into database:
org.hibernate.HibernateException: The database returned no natively generated identity value
I am using the following code:
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
session.save(user);
logger.info("Successfully data insert in database");
tx.commit();
isSaved = true;
Please let me know what is wrong. Thankx
It seems as if the database doesn't support the identity id generator. Based on your mapping you are probably using the userName as the ID column, which would mean that you probably want to set the generator class to assigned since the username (= id) will be picked manually (and not auto generated by the database):
<hibernate-mapping>
<class name="com.test.User" table="user">
<id name="userName" column="user_name">
<generator class="assigned" />
</id>
<property name="userCode">
<column name="user_code" />
</property>
</class>
</hibernate-mapping>