0

I have the following code:

List<Assignment> assignments = objectContext.performQuery(assignmentQuery);
objectContext.commitChanges();
objectContext.deleteObjects(assignments);
objectContext.commitChanges();

I do the first commitChanges() to commit all the queries. Then I clear Cayenne's log. On the second commitChanges(), this shows up on the log:

INFO : QueryLogger.logBeginTransaction: 2013-07-10 07:37:11,214: --- transaction started. INFO : QueryLogger.logQuery: 2013-07-10 07:37:11,218: INSERT INTO scheduler_assignment ... INFO : QueryLogger.logQuery: 2013-07-10 07:37:11,241: DELETE FROM scheduler_assignment ... INFO : QueryLogger.logCommitTransaction: 2013-07-10 07:37:11,286: +++ transaction committed.

I don't understand why it is doing the INSERT statement when I'm trying to delete. Can anyone explain? Thanks!

Tuan
  • 1,476
  • 13
  • 23

1 Answers1

1

The only logical explanation is that your ObjectContext is "dirty" - it contains other uncommitted objects in addition to what is shown here. This can happen for a variety of reasons, 2 most common being:

(1) ObjectContext scope is too wide and changes to the context are originating from some other place in the app.

(2) changes originating from callbacks/listeners during commit.

Some hints on scoping of ObjectContexts:

  • Do not share ObjectContexts in a concurrent environment if the contexts are expected to handle writes (as opposed to just reads; read-only contexts can be shared).
  • Ideal scope for an ObjectContext that handles writes is a single method or a single request. This guarantees that nobody else would access it concurrently.
  • Often a context would have a longer scope though. E.g. it may be saved in a session in a webapp, and may carry uncommitted changes between requests. In this situation still consider reducing its scope. E.g. create multiple such contexts in a session, each attached to a given page. So that uncommitted changes in one place do not surprise you when you commit something else in another place.
andrus_a
  • 2,528
  • 1
  • 16
  • 10
  • Thanks for answering. Do you have any theory for why it would still contain the uncommitted objects after the first call to `commitChanges()`? Shouldn't the first call go through all of the uncommited objects and commit them? – Tuan Jul 10 '13 at 20:53
  • Yes. After the first commit you should get either a clean context or an exception. Try calling context.newObjects() after commit #1 and then before commit #2 to see if there's anything there. Honestly I still can't think of any reason other than some other thread concurrently adding those objects. Also is above the actual code or is there something else happening between the 2 commits in the actual app? – andrus_a Jul 11 '13 at 12:48
  • Just thought of another possible cause - do you have any @PreRemove callbacks or listeners on Assignment entity? Those might fire and create the objects (if there is a code to do that) – andrus_a Jul 11 '13 at 13:03
  • Thank you for the tip! I found that there are preUpdate callbacks from other objects that were ran on prior to commitChanges(). Side question though: so if I have two objects, A and B. Both has PreUpdate callbacks. Once commitChanges is called, the callbacks from both objects will be activated. Is that correct? – Tuan Jul 11 '13 at 18:10
  • Yep, looks like the callbacks from both objects are triggered. Thanks again for the help. – Tuan Jul 11 '13 at 23:17
  • Only if both A and B have changes in this context. Even if those are "phantom" changes, such as adding an object to to-many relationship. – andrus_a Jul 12 '13 at 06:55