-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: Can you create a Blank Transient Entity? *RESOLVED*
PostPosted: Sun Feb 03, 2008 7:02 pm 
Newbie

Joined: Fri Jan 25, 2008 8:00 am
Posts: 11
*RESOLVED* SEE MY LAST POST IN THIS THREAD.

Say for instance I have a mapping of:

Code:

<class entity-name="Foo" name="beans.hibernate.HibernateFoo">



Is there anyway to get the hibernate session to create me a new HibernateFoo, that is transient and blank (i.e. has no ID).

Failing that, is there any way to pass a hibernate class the entity name "Foo", and have it return the class name or class "beans.hibernate.HibernateFoo".

The reason I don't just call "new HibernateFoo" is because my app is decoupled from the data source behind a Data Access Object design pattern, therefore calling "new HibernateFoo" would defeat the purpose of using the DAO design pattern. i.e. I need to delegate the call to my DAO, for it to return the specific subtype.

Thanks.


Last edited by Pulseammo on Tue Feb 05, 2008 4:49 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 04, 2008 4:07 pm 
Newbie

Joined: Fri Jan 25, 2008 8:00 am
Posts: 11
Sorry folks, I know this is bad form but, I guess this is a bit of a bump.

Even if someone could post a link to a part in a manual or anything so that I can go and read it. (I can't find what I'm looking for in the official hibernate manual).

Thanks again!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 04, 2008 4:34 pm 
Regular
Regular

Joined: Mon Aug 20, 2007 6:47 am
Posts: 74
Location: UK
I think the way to keep an object transient is to instantiate it outside of an open hibernate session.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 04, 2008 6:09 pm 
Newbie

Joined: Fri Jan 25, 2008 8:00 am
Posts: 11
Irons UK wrote:
I think the way to keep an object transient is to instantiate it outside of an open hibernate session.


First of all, thanks for the reply, I appreciate it :).

But unfortunately I can't just instantiate the object, since I'm trying to decouple by app from my specific hibernate classes.

i.e. if I had a User abstract class, my UserDao returns a User, but my HibernateUserDao will return a HibernateUser. That's alright for DAO classes returning things, but if I need to create a new user and put it into my database, I can't call "new HibernateUser" as I'm now coupled to my hibernate classes instead of my DAO interface, therefore my DAO interface needs to provide new User objects of the type specific to the current DAO Factory.

But yes, if I wasn't trying to use a DAO design pattern, then I'd just create a new HibernateUser object. But right now, my hibernate mapping file is the only place that knows that entity-name="User" is mapped to name="beans.HibernateUser", and I somehow need that information back.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 05, 2008 4:47 pm 
Newbie

Joined: Fri Jan 25, 2008 8:00 am
Posts: 11
Alright, I've resolved this.

Say you have the mapping:

Code:
<class entity-name="Foo" name="org.company.beans.HibernateFoo">


Where "HibernateFoo" extends org.company.beans.Foo.

You have a DAO interface with a create method:

Code:
public interface FooDao {

public Foo create();

}


and you have business code:

Code:
public makeNewFooAndSave() {
Foo f = DaoFactory.getFactory().getFooDao().create();

DaoFactory.getFactory().getFooDao().save(f);
}


Note this business code is not coupled in any way to hibernate, so you could easily switch out the hibernate DaoFactory to an XML DaoFactory say.

Now, the resolution:
Code:

public class HibernateFooDao extends FooDao {

public Foo create() {
Session s = SessionFactory.getCurrentSession();

Class<Foo> foo = SessionFactory().getClassMetaData("Foo").getMappedClass(s.getEntityMode());

return foo.newInstance();
}

}


As can be seen, getMappedClass will get you the Class type of the mapped entity-name. In this example I plugged the value "Foo" into the meta data manually, this doesn't need to happen if you use reflection and type parameters as per the HibernateDao tutorial in the wiki (see the GenericHibernateDao class).

I don't know if this is the fastest way to pull this off, but there you are if anyone else needs it.

P.S Thanks again for your reply again Irons.

Good luck to anyone who finds this thread as well if they ever need it.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 06, 2008 5:36 am 
Regular
Regular

Joined: Mon Aug 20, 2007 6:47 am
Posts: 74
Location: UK
Pulseammo, I've been following this thread out of interest. Can you help me understand how you have created a transient instance of Foo in your code example?

From what I understand the instance of Foo will be persisted when you flush the session. Is this not the case?

Thanks,

-Irons


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 06, 2008 8:09 am 
Newbie

Joined: Fri Jan 25, 2008 8:00 am
Posts: 11
Irons UK wrote:
Pulseammo, I've been following this thread out of interest. Can you help me understand how you have created a transient instance of Foo in your code example?

From what I understand the instance of Foo will be persisted when you flush the session. Is this not the case?

Thanks,

-Irons


Of course, I'll try to explain as best as I can (Long post coming up, skip to "HERES THE ANSWER" if you want it in short ;P).

Ok, first it's important to know a bit about a certain feature of Java, to do with the class loader, I think (I'm not quite sure, this may be part of the reflection API).

So first, you need to know the "different" way to instantiate a class without using the "new" keyword, lets take an example:

Code:

String s = String.class.newInstance();



The above code is just like calling:

Code:

String s = new String();



(i.e. the new keyword is prolly just some syntactical sugar).

When calling String.class, a Class object is returned, with the parametrised type (as in generics) of String, in full Class<String>.

Now, why does this matter? In hibernate you can map with:

Code:

<class entity-name="Foo" name="beans.HibernateFoo" table="foo">



i.e. I've simplified my mapping name down to "Foo" instead of "beans.HibernateFoo". So at runtime I need to know, what Class object has the string "Foo" been mapped to? This is held inside the SessionFactory.getClassMetaData(String entity-name) mapping.

Now, if I call something in hibernate like:

Code:

Session s = SessionFactory.getCurrentSession();

s.get("Foo", 1);



first of all, that ID needs to exist in the database, and second of all, yes, the get method will generate a persistent object (it's obviously also not a blank object etc, but the idea here is the a method called on session is linked into the persistence stuff).

Now HERE's THE ANSWER COMING UP ;)!

The reason that hibernate doesn't create a persistent object, is because the code:

Code:

SessionFactory.getClassMetaData("Foo").getMappedClass(EntityMode e);



is NOT linked to the database or persistence mechanism, it is only a mapping file generated from your XML, one of whose functions is to return a entity-name to Class object mapping (getMappedClass method).

In this case, getMappedClass will return a Class<Foo> object, and using the beginning of my post, you use plain old java tricks to instantiate a new one:

Code:

Class<Foo> f = SessionFactory.getClassMetaData("Foo").getMappedClass(EntityMode e);

Foo f = f.newInstance();



Remembering all the while that newInstance() is in no way linked to hibernate, and that Foo is merely an interface! You've therefore decoupled your app, and got your DAO class to build you a new HibernateFoo.

NOTE:
This only has purpose if you use the GenericHibernateDao abstract superclass for your DAO subclasses, if you don't, then you may as well hardwire each of your DAO class create methods to return their specific subtype, then you're still decoupled:

Code:

public class HibernateFooDao implements FooDao {


public Foo create() {
return new HibernateFoo();
}

}



This would also be ok, but you have masses of extra code to write by not using the GenericHibernateDao class found here:

http://www.hibernate.org/328.html

I hope this wasn't too much of a difficult read there. Does that make sense Irons? I can try again ;). Also, you understand why I want to do things this way with the generic hibernate dao classes rather than hard wire each individual dao right?

Hope this helps!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 06, 2008 8:27 am 
Regular
Regular

Joined: Mon Aug 20, 2007 6:47 am
Posts: 74
Location: UK
Thanks for taking the time to write this out =)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.