Mitesh Meswani wrote:


Allen Gilliland wrote:


Mitesh Meswani wrote:


Dave wrote:
On 1/18/07, Mitesh Meswani <[EMAIL PROTECTED]> wrote:
> if(object.id != null)
>   update()
> else
>   save()

This would be true if the id is generated as is the case with Roller.
For objects where id is user supplied, above algorithm can not be used.
Thats the reason some frameworks (for example JPA) does not provide
equivalent of saveOrUpdate() method.

Yes, that is true and it is the case with the property object, whose
ID is the name property.

And, we can't rely on object.id because we don't know which field is
the id. So, for JPA you'd have to do something like this in the store
method:

       EntityManager em = getEntityManager(true);
       if (!em.contains(obj)) {
           // If entity is not managed we can assume it is new
           em.persist(obj);
       }
       return obj;
Above has a performance penalty to pay and it assumes that no detached object will be ever passed to store(). Currently, I don't think that is true. For example, I found following with a quick search
Class MaintenanceAction {

....
   public ActionForward flushCache(
           ActionMapping       mapping,
           ActionForm          actionForm,
           HttpServletRequest  request,
           HttpServletResponse response)
           throws IOException, ServletException {
             try {
RollerRequest rreq = RollerRequest.getRollerRequest(request); -----> WebsiteData website = rreq.getWebsite(); // I think this is a detached object
           RollerSession rses = RollerSession.getRollerSession(request);
                     if ( rses.isUserAuthorizedToAdmin(website) ) {
// some caches are based on weblog last-modified, so update it
               website.setLastModified(new Date());
                             try {
UserManager umgr = RollerFactory.getRoller().getUserManager(); -----> umgr.saveWebsite(website); // The save will not work as it will end up calling persist


Actually, that shouldn't be a detached object because the RollerRequest class should be querying for the object on each request.In any case though, the main point is as Dave suggested before, we will *NOT* support the saving of detached objects anymore and anywhere that does it now is considered a bug and needs to be fixed.
Great. So, the approach suggested by Dave should work. I remember seeing detached objects being used in the test code which we can fix as required.

But, I still think that the code will be cleaner if we distinguish between saving a new object vs. updating an existing object. Most of the calls to Manager#save() are on managed object and can be removed. The JPA implementation currently use the information about whether save is called for insert or update to maintain relationships as below.
Class DatamapperWeblogManagerImpl {
.....
   public void saveWeblogCategory(WeblogCategoryData cat)
           throws RollerException {
......
if(!PersistentObjectHelper.isObjectPersistent(cat)) { <<-- A workaround to findout whether we are here for insert or update
           // Newly added object. If it has a parent,
           // maintain relationship from both sides
           WeblogCategoryData parent = cat.getParent();
           if(parent != null) {
               parent.getWeblogCategories().add(cat);
           }
       }
We will need to find another workaround for above if the save() call comes for both insert and update


I suppose it's debatable which approach is cleaner, but my preference is to maintain the current code the way it is and I think that will work fine for any backend implementation.

One thing that I am not okay with is removing the need for a call to XXXManager.save() for updating managed objects. The problem with doing that is that it requires the backend implementation to use some kind of ORM type object management solution. i.e. If I wanted to take the current Roller code and rip out Hibernate and create my own manager impls using raw jdbc coding then that is possible right now and it wouldn't be if we removed calls to save() for all update action.

For your example, I think we should look more closely at the need for maintaining the relationship on both ends, but regardless of that I think the example may not be doing the right thing. When I want to add a new category X to a parent category Y then I think the proper code is ...

Category X = new Category();
Y.addCategory(X); (this triggers getWeblogCategories().add(X) and X.setParent(Y))
mgr.saveCategory(Y);

As I understand it, that is how Hibernate and other ORM solutions want you to handle the persistence of parent/child relationships.

-- Allen



-Mitesh


-- Allen



-Mitesh

- Dave

Reply via email to