|
#1
|
|||
|
|||
|
HibernateTemplate has the saveOrUpdate method, but JpaTemplate doesn't. JpaTemplate has merge and persist methods. Is it very difficult to write mergeOrPersist method for JpaTemplate?
Right now I have to use a class called DaoUtils (it's from AppFuse 2.0M3) to know when to persist and when to merge. That file is here: Code:
public class DaoUtils {
protected static final Log log = LogFactory.getLog(DaoUtils.class);
private static final String GET_INITIALS = "get";
@SuppressWarnings("unchecked")
public static Object getPersistentId(Object o) throws PersistenceException {
Object objId = null;
final String eMsg = "Error executing get<IdValue> method on persistent class.";
String logMsg = "Persistent identity for object of type '?1' is accessible with method '?2'";
boolean hasId = false;
boolean fieldIsAnnotated = false;
try {
final AccessibleObject annotatedAccessibleObject = getAnnotatedAccessibleObject(
o.getClass(), Id.class, EmbeddedId.class);
if (annotatedAccessibleObject != null) {
log.debug("'" + annotatedAccessibleObject + "' was annotated as the identifier of '" + o.getClass().getName() + "'");
hasId = true;
Method getter = null;
if (annotatedAccessibleObject instanceof Method) {
getter = (Method) annotatedAccessibleObject;
} else if (annotatedAccessibleObject instanceof Field) {
fieldIsAnnotated = true;
getter = findGetter(o.getClass(),
((Field) annotatedAccessibleObject).getName());
}
objId = getter.invoke(o);
if (log.isDebugEnabled()) {
logMsg = logMsg.replace("?1", o.getClass().getName());
logMsg = logMsg.replace("?2", getter.getName());
log.debug(logMsg);
}
}
} catch (IllegalArgumentException e) {
throw new PersistenceException(eMsg, e);
} catch (IllegalAccessException e) {
throw new PersistenceException(eMsg, e);
} catch (InvocationTargetException e) {
throw new PersistenceException(eMsg, e);
} catch (SecurityException e) {
throw new PersistenceException(eMsg, e);
} catch (NoSuchMethodException e) {
if (fieldIsAnnotated) {
throw new PersistenceException("A field (as opposed to a method) " +
"was annotated as the identifier of '" + o.getClass().getName() +
"', but a no corresponding getter method conforming to " +
"JavaBean conventions was found." , e);
} else {
throw new PersistenceException("Attempting to invoke getter method " +
"to return the identifer of '" + o.getClass().getName() + "' failed.", e);
}
}
if (!hasId) {
throw new PersistenceException("Object of type '"
+ o.getClass().getName()
+ "' does not have an @Id or @EmbeddedId annotation.");
}
return objId;
}
private static AccessibleObject getAnnotatedAccessibleObject(Class c, Class<? extends Annotation>... annotations)
throws PersistenceException {
final Set<AccessibleObject> members = new HashSet<AccessibleObject>();
members.addAll(Arrays.asList(c.getDeclaredMethods()));
members.addAll(Arrays.asList(c.getDeclaredFields()));
for (AccessibleObject member : members) {
for (Class<? extends Annotation> annotation : annotations)
if (member.isAnnotationPresent(annotation))
return member;
}
if (c.getSuperclass() != null)
return getAnnotatedAccessibleObject (c.getSuperclass(), annotations);
return null;
}
private static Method findGetter(Class type, String property) throws NoSuchMethodException {
String methodName = GET_INITIALS
+ Character.toUpperCase(property.charAt(0))
+ property.substring(1);
return type.getMethod(methodName);
}
}
|
|
#2
|
|||
|
|||
|
I'm not much of a JPA expert, but doesn't merge do this for you?
http://www.hibernate.org/hib_docs/en...single/#d0e897 |
|
#3
|
|||
|
|||
|
That's the way it I thought it read too, but in practice, it threw an exception.
|
|
#4
|
|||
|
|||
|
If that's the case, the reference manual doesn't seem very useful. Either that or I'm really reading it wrong.
Quote:
Code:
// In the first entity manager Cat cat = firstEntityManager.find(Cat.class, catID); // In a higher layer of the application, detached Cat mate = new Cat(); cat.setMate(mate); // Later, in a new entity manager secondEntityManager.merge(cat); // update existing state secondEntityManager.merge(mate); // save the new instance |
|
#5
|
|||
|
|||
|
Yeah... it was surprising and frustrating to me to, as I read it the same way you are. I don't have the exact exception it gave me at the time, but the difference may be explained by this piece of the documentation.
<quote> Merging vs. saveOrUpdate/saveOrUpdateCopy Merging in EJB3 is similar to the saveOrUpdateCopy() method in native Hibernate. However, it is not the same as the saveOrUpdate() method, the given instance is not reattached with the persistence context, but a managed instance is returned by the merge() method. </quote> |
|
#6
|
|||
|
|||
|
but it seems to me that you are
You answers (at least until now) are very accurate. Thank you.
|
|
#7
|
|||
|
|||
|
So, more detail can be seen here if anyone is interested or has any feedback. Thanks...
http://www.nabble.com/Do-we-need-Dao....html#a9463723 If you want to get to that code: https://appfuse.dev.java.net/servlets/ProjectSource The specific module being referred to: https://appfuse.dev.java.net/source/...jpa-hibernate/ |
|
#8
|
|||
|
|||
|
This was bothering me, so I started playing around with it a bit more. In order to get this to work, we'd have to change the UniversalDao (and UniversalDaoJpa of course) to return the result of the entityManager.save method. (The same obviously applies to UserDao and UserDaoJpa.)
EG... UniversalDao.save should become: public Object save(Object o); UniversalDaoJpa.save should become: public Object save(Object o) { return this.entityManager.merge(o); } Line 41 of UniversalDaoTest should change from: universalDao.save(user); ... to: user = (User)universalDao.save(user); That makes the test past. The documentation was right, I just wasn't using the method correctly. The difference in laymen's terms between JPA's merge and Hibernate's saveOrUpdate is that saveOrUpdate copies the newly managed persistent state onto the object passed into the method, and merge does not. |
|
#9
|
|||
|
|||
|
Quote:
. Thanks for posting back!
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|