I am including my code because I hope other people find it interesting. For the most part I can just call a generic Struts action and Autosave most of my forms now....pretty slick actually. My environment is Struts, Spring and Hibernate.
Can anyone tell me how the resolveIdentifier() in the Hibernate Metadata Type Interface is supposed to work? I think it is what I need to get my auto copy/save completely working. If it does not sound like what I need could I get a suggestion?
The JavaDocs read the parameters as such...could anyone elaborate, and why do I need to send the session in? I'm not even sure if I have access to the current sesson using Spring's injection.
value - an identifier or value returned by hydrate()
owner - the parent entity
session - the session
I wrote a service that will take a transfer object (Bean/POJO) and automatically copy the contents over into a mapped Hibernate domain object. So basically what it does is create an instance of the domain object, and then looks to see if the transfer object has a primary key value. If it does then it retrieves the values from the database. Next I use the BeanUtils to copy all the values from the transfer object over to the domain object. Lastly, I walk over the domain object and figure out the foreign key dependancies and create instances of those classes to put back in my domain object...because that is what Hibernate foreign keys are, mapped objects.
The limitation of my design is if I have a foreign key to a table where the foreign key name is different than the primary key name of the parent table I cannot automatically generate an object. Does that make sense? If I have a table called Users with a primary key of user_id, and I have a table called Requests with a foreign key of assignee_id I do not know how to deal with it. If assignee_id was in fact named user_id then I would normally say, ok I found a User object in the domain object, its primary key is user_id, so look in my transfer object for a user_id....doesn't work when the foreign key is called assignee_id.
I believe that the resolveIdentifier() method will fix my problem, but I have no clue on how to use it...and this is a service that uses Spring, so I do not know if that complicates things or not.
I hope this code example paste in ok, if not I could send it.
/**
* First creates a domain object of the specified type. If the domain's primary key is populated
* then will retrieve all the domain information. Then will use the BeanUtils.copy function to
* copy the data from the transfer object (usually a form or POJO) to the domain object. Then will
* go through all the entity foreign key relationships and create objects for those as well.
*
* It is very important to note that all values from the transer object will be directly copied into the domain object.
* This could potentially cause conflicts...ie if you have a transfer attribute that is the same and a domain object reference
* you will get a class cast exception.
*
* TODO: figure out how to get the foreign key name if it is not named the same as the joining table.
* Right now to get around the problem is to populate the field after get the copy
*
* @param domainClass The domain object we are trying to get a copy of
* @param transfer The transfer object (usually a form Bean or POJO) that contains the data to copy to the domain object
*/
public Object copy(Class domainClass, Object transfer) throws Exception
{
Object domain = domainClass.newInstance(); //first create a new instance of the domain object
SessionFactory sessionFactory = getSessionFactory();
ClassMetadata meta = sessionFactory.getClassMetadata(domain.getClass()); //get the meta information for the domain object
String metaPrimaryKey = meta.getIdentifierPropertyName();
Object keyValue = PropertyUtils.getProperty(transfer, metaPrimaryKey);
logger.debug("domain primary key " + metaPrimaryKey + " " + keyValue);
if ((keyValue != null) && StringUtils.isNotEmpty(keyValue.toString())) //if have a primary key then get the values
{
BeanUtils.copyProperty(domain, metaPrimaryKey, keyValue);
domain = (Object) getHibernateTemplate().load(domain.getClass(), new Long(keyValue.toString())); //get a copy so do not have to worry about overwriting values that our form does not have
}
BeanUtils.copyProperties(domain, transfer); //do a blind copy of everything from the transfer object to the domain object.
Type[] types = meta.getPropertyTypes();
String[] names = meta.getPropertyNames();
for (int i = 0; i < names.length; i++)
{
String name = names[i];
Type type = types[i];
if (type.isEntityType() && type.isAssociationType()) //only deal with foreign key entity relationships...
{
Class entityDefinition = type.getReturnedClass(); //get the entity class
ClassMetadata entityMeta = sessionFactory.getClassMetadata(entityDefinition); //get the entity meta data
String entityMetaPrimaryKey = entityMeta.getIdentifierPropertyName(); //get the entity primary key
Object primaryKeyValue = getPrimaryKeyVaue(transfer, entityMetaPrimaryKey); //get the primary key from the transfer object
if (primaryKeyValue != null)
{
Object entity = entityDefinition.newInstance(); //get a new instance of the entity
BeanUtils.copyProperty(entity, entityMetaPrimaryKey, primaryKeyValue); //copy the primary key value into the new entity we created
meta.setPropertyValue(domain, name, entity); //set the entity on the domain class
}
}
}
return domain;
}
/**
* Get the primary key out of the transfer object.
* Split out to be more obvou
*/
public Object getPrimaryKeyVaue(Object transfer, String primarykey) throws IllegalAccessException, InvocationTargetException
{
try
{
return PropertyUtils.getProperty(transfer, primarykey);
}
catch (NoSuchMethodException e)
{
logger.debug("warning -- problem finding the foreign key in the transfer object : " + primarykey + " -- this may not be a problem though.", e);
}
return null;
}
-Jeff
|