Shaolinq icon indicating copy to clipboard operation
Shaolinq copied to clipboard

AfterCommit DataAccessModelHook

Open samcook opened this issue 6 years ago • 2 comments

The BeforeSubmit and AfterSubmit hooks fire before and after a submit (i.e. flush) to the database, however:

  • this can happen multiple times per transaction, depending on when things are actually sent to the database
  • the records may not actually end up being committed if the transaction is rolled back

Having an AfterCommit hook (which includes all the records that were committed) would be most useful.

samcook avatar May 23 '19 12:05 samcook

Hi @samcook,

For context: The IDataAccessModelHook system was designed to be lightweight in terms of memory usage. This is why the DataAccessModelHookSubmitContext.New, DataAccessModelHookSubmitContext.Updated, DataAccessModelHookSubmitContext.Deleted properties are enumerables rather than lists - they are windows onto existing data structures within the current internal transaction. The hooks system was also designed to reflect the commands sent to the database as it happens rather than the end state of the database (a replay log of sorts).

After a flush is called, information related to the flushed changes are lost. For example, an object that was updated won't be identifiable as having been updated within the context of the transaction at the next flush or commit time. Shaolinq doesn't keep lists of "updated" objects so much as keep a transaction-local cache of all objects with each having state flags.

A solution without changing the lightweight nature of the hooks would be to add BeforeRollback and AfterRollback. This would of course mean that any actions you take in response to BeforeSubmit and AfterSubmit would need to take rollback into account. You could queue these actions and either throw away the queue on rollback or process them at commit time. You can detect whether a submit is an actual flush or commit via the DataAccessModelHookSubmitContext.IsFlush property.

If you use a queue to keep track of actions to take, it should also happily deal with the situations where a transaction acts on the same object across multiple flushes but within the same transaction (e.g. create object -> flush -> update object -> flush -> delete object). You would just perform each action in queue order (something that wouldn't easily be represented within a single AfterCommit call). An optimization could be added to coalesce these actions into a no-op but then that kind of logic would be determined by the app rather than by Shaolinq which (as stated above) is merely reflecting the commands sent to the database.

Does adding rollback callbacks sounds like a reasonable solution?

tumtumtum avatar Jun 11 '19 21:06 tumtumtum

@samcook Any comments?

tumtumtum avatar Jun 25 '19 17:06 tumtumtum