Allen Gilliland wrote:
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.
I see the point about not doing away with save(). But it is also not a
good idea to depend on the "magic" that saveOrUpdate() performs to
determine whether its an insert or update to database. For example, the
manager using raw jdbc will either need a trip to database or maintain
some cache to determine whether to issue an insert or update in response
to save(). How about separating save() into two methods say persist() to
insert objects and update() to update objects and call appropriate
method from the frontend.
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.
I agree. The code in Datamapper*Manager is a workaround. Current roller
frontend code needs to change to use above pattern
-Mitesh
-- Allen
-Mitesh
-- Allen
-Mitesh
- Dave