Bug #871
closeddbo::collection::find() causes subsequent changes to be discarded
0%
Description
Hello!
Calling of dbo::collection::find() (or methods of returned query) seems to cause premature sql-update, apparently resulted in discarding of subsequent changes of dbo-object.
patch of examples/feature/dbo/tutorial2.C is attached
Output (last transaction):
begin transaction
update "post" set "version" = ?, "user_id" = ? where "id" = ? and "version" = ?
insert into "tag" ("version", "name") values (?, ?)
select count(1) from "tag" join "post_tags" on "post_tags"."tag_id" =
"tag"."id" where ("post_tags"."post_id" = ?) and (id = ?)
select count(1) from "post" join "post_tags" on "post_tags"."post_id" =
"post"."id" where "post_tags"."tag_id" = ?
0 post(s) tagged with Cooking.
commit transaction
Tag was not added to post->tags.
If post->modify() is runned again before transaction.commit(), tag is added.
It is likely to be the one way to work around.
PS This qery is used to make sure that this tag has not been added to this post.
Could you provide more convenient way to do this?
Files
Updated by Boris Nagaev over 13 years ago
Patch is attached not to improve the tutorial example, but to demonstrate possible bug of dbo::collection
Updated by Koen Deforche over 13 years ago
- Status changed from New to Resolved
- Assignee set to Koen Deforche
Hey,
While this particular case could be fixed (and I did), since a collection can mark its owning object dirty, just like modify() does, taking the modify() pointer and caching it will in general not work.
The modify() method marks the object dirty. Any querying flushes the transaction since changes may impact the query result.
(The modify() method is the one part of the Wt::Dbo API that is clumsy ... and that D could do better :-) )
Regards,
koen
Updated by Boris Nagaev over 13 years ago
Thanks,
are there other cases when caching of modify() result can cause problems?
If model class has private data members (such as collection) and public accessors, user of this class is to use modify() only once (calling public method). Inside public method, modify() can't be recalled (since Dbo object can't get it's ptr pointer, while loading new ptr from session is useless).
Is it necessary to query to mark object as non-dirty after flushing?
Off-topic:
Could you provide way to get current ptr from Dbo object?
It can be usefull also while adding current object to collection from other object.
Updated by Koen Deforche over 13 years ago
Hey Starius,
Now I see how this is indeed a fundamental problem, and not one I previously considered.
I've added a self() method to the Wt::Dbo::Dbo base class which returns the current ptr<> and also a setDirty() method.
In this way you could end your public method that modifies the object with a call to setDirty() to eliminate the problem of intermediate flushing.
Regards,
koen
Updated by Boris Nagaev over 13 years ago
Hello!
collection.size() seems also to act as collection.find() used to do. After collection.size(), Dbo object is saved to database and marked as non-dirty, so subsequent changes of Dbo are not saved.
Updated by Koen Deforche over 13 years ago
Hey Starius,
I found a way to make modify() return a proxy object which outlives the dereference operator, and marks the object dirty from its destructor.
In this way, it will always correct to call a public method on the object and be sure it is marked dirty.
I'll try to commit this to git later today.
Regards,
koen
Updated by Koen Deforche over 13 years ago
- Status changed from Resolved to Closed