Supporting my concurrency scheme

Posts   
 
    
Innes avatar
Innes
User
Posts: 45
Joined: 18-Jun-2004
# Posted on: 22-Jun-2004 16:01:30   

I've just started using LLBLGEN, and I'm not very knowledgeable on the various hookpoints available for the various generated code types, and their various capabilities. I am using the Adaptor code generation templates.

So...

Concurrency Scheme My (Oracle) database supports concurrency via a '_change control count_' field (term I just made up sunglasses ) on each table, and update triggers on each table that check whether, for every UPDATE, the update increments the CCC field. So, to recap, in order for an update to succeed, the client has to make sure they increment the CCC field.

If any update fails to increment this CCC field from the existing database value to a value one higher, then the update fails, since it looks like the update is a change to an out-of-date version of the record, or it's being attempted by somebody who doesnt know about what they should be doing to the CCC field.

It's a bit like an implementation of SQLServer's timestamp field with integrated concurrency checking added.

What I Want to Achieve What I would like to achieve is for my DAL to deal with the CCC field, so that the programmer (me!) doesnt have to remember to manually increment it field whenever he saves changes to an entity.

As I understand it, it's possible to inject WHERE clauses into UPDATES via predicate factory, but in this case, I need to inject a field update ("CCC=:ccc_plus1").

Does anyone have any ideas as to how to achieve this goal? Will it need a modification of the templates? Can I subclass DataAccessAdaptor to insert this functionality? etc...

edit: I found a place in DataAccessAdaptor base where, if I had the chance, it looks like I could update the CCC field, and let the existing code take its course. No idea if that approach would actually work. (before // retrieve persistence information In SaveEntity method)

netclectic avatar
netclectic
User
Posts: 255
Joined: 28-Jan-2004
# Posted on: 22-Jun-2004 16:28:33   

Innes wrote:

edit: I found a place in DataAccessAdaptor base where, if I had the chance, it looks like I could update the CCC field, and let the existing code take its course. No idea if that approach would actually work. (before // retrieve persistence information In SaveEntity method)

Yes, this (kind of) is how i handle concurrency, by overriding the SaveEntity method and doing various checks/updates. If you have a search around i think you'll find various threads recommending this method.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 22-Jun-2004 16:33:18   

Overriding SaveEntity() in a derived DataAccessAdapter class is indeed the way to go for this. Not OnSaveEntity() because that's too late, the query is then already created.

I'm not sure if your scheme is safe though. If 2 users are updating the same row, both are updating the CCC field to the same value.

Frans Bouma | Lead developer LLBLGen Pro
Innes avatar
Innes
User
Posts: 45
Joined: 18-Jun-2004
# Posted on: 22-Jun-2004 17:15:35   

Otis wrote:

Overriding SaveEntity() in a derived DataAccessAdapter class is indeed the way to go for this. Not OnSaveEntity() because that's too late, the query is then already created.

I'm not sure if your scheme is safe though. If 2 users are updating the same row, both are updating the CCC field to the same value.

The safety is in the update trigger. The first user is successful, because they update CCC to CCC+1. (NB: with an explicit set to a numeric value, not to "CCC + 1". The second user fails, because by that point their update doesnt set CCC to the correct value.

e.g: Client1 reads record (ccc=12) Client2 reads record (ccc=12) Client1 updates record (ccc=13) Trigger compares 13 to CCC -> okay. Client2 updates record (ccc=13) Trigger compares 13 to CCC -> BAD (13 != CCC+1) update fails.

At least, I hope it makes sense! confused simple_smile

Innes avatar
Innes
User
Posts: 45
Joined: 18-Jun-2004
# Posted on: 22-Jun-2004 17:18:35   

netclectic wrote:

Innes wrote:

edit: I found a place in DataAccessAdaptor base where, if I had the chance, it looks like I could update the CCC field, and let the existing code take its course. No idea if that approach would actually work. (before // retrieve persistence information In SaveEntity method)

Yes, this (kind of) is how i handle concurrency, by overriding the SaveEntity method and doing various checks/updates. If you have a search around i think you'll find various threads recommending this method.

Okay, I have been trying to get the 2-class templates (generates a derived entity class) working on my machine so I could embed the code into the entities (override the method that returns 'affected fields' of an entity or something), but overriding SaveEntity will be easier.

Thanks, folks.

Innes avatar
Innes
User
Posts: 45
Joined: 18-Jun-2004
# Posted on: 22-Jun-2004 18:14:17   

Yay. I've tested it once, so it must be completely working simple_smile :


public override bool SaveEntity(...)
{

    // Updating an existing entity?
    if (!entityToSave.IsNew)
    {
        IEntityFieldCore cccField = entityToSave.Fields["Ccc"];
        if (!cccField.IsChanged)
        {
            cccField.CurrentValue = (Int64)(cccField.CurrentValue) + 1;
        }
    }
    return base.SaveEntity (entityToSave, refetchAfterSave, updateRestriction, recurse);
}

The IsChanged check is in case the entity has already had its Ccc field updated (I wasnt sure whether recursive mumble mumble blah blah...)

_Is updating Ccc via the CurrentValue property the right way to do it? _

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 22-Jun-2004 18:40:43   

Innes wrote:

_Is updating Ccc via the CurrentValue property the right way to do it? _

That will bypass a set validator. Best is to use: entityToSave.SetNewFieldValue("Ccc", (Int64)(cccField.CurrentValue) + 1);

simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Innes avatar
Innes
User
Posts: 45
Joined: 18-Jun-2004
# Posted on: 23-Jun-2004 09:49:10   

Otis wrote:

Innes wrote:

_Is updating Ccc via the CurrentValue property the right way to do it? _

That will bypass a set validator. Best is to use: entityToSave.SetNewFieldValue("Ccc", (Int64)(cccField.CurrentValue) + 1);

simple_smile

That's the kind of thing I was concerned about. But, come to think of it, in this case I shouldn't need any validation performed on the field.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 23-Jun-2004 10:20:24   

If you don't use a validator object, just set the CurrentValue property simple_smile . It does a type check so that's not something to worry about. For string/byte array fields, it doesn't do the length check as SetNewFieldValue() will do.

Frans Bouma | Lead developer LLBLGen Pro