Deferred transaction updates idea.
Posted: Fri Aug 07, 2009 10:55 am
by Carl Ranson >> Mon, 22 Mar 2004 5:59:55 GMT
Ok, I've just been dealing with a situation which has prompted me to moot this idea.
Imagine you had a company and employees class. There is a one to many relationship between company and employees.
Employee has an integer yearly sales figure. Company has a integer attribute on it called topEmployeeSales that is a copy of the yearly sales figure for the employee with the largest yearly sales. Imagine this is done for performance reasons (many employees) and that topEmployeeSales is used as a dictionary key.
The question is, how do you ensure the topEmployeeSales is updated correctly in ALL cases AND that you don't do excessive overcalculation of it.
You can update it whenever the yearly sales is set for any employee and when an employee is added or removed, but that involves calculating it each time. This is fine if you change them one at a time, but is silly if you are doing batch updates of employees.
You can have some background process that causes it to be periodically updated but that means it won't be guaranteed correct if read between the employee update and the company update.
An elegant solution would be a mechanism in Jade whereby an object can be flagged as dirty and a special "transactional" method can be called just before the commit transaction. I would envision something similar to a causeEvent call except that it gets called before the transaction is complete.
Then you could calculate the derived fields once and only once per transaction.
it code it might look something like.
employee.setYearlySales(sales : Integer);begin
yearlySales := sales;
myCompany.causeTransactionalEvent(Event_Update_Top_Sales);
end;
company.transactionalEvent(eventType: Integer);begin
if eventType = Event_Update_Top_Sales then
// calculate and store top yearly sales...
endif;
end;
and then you could have
begin
Transaction
foreach employee in company.allEmployees do
employee.setYearlySales(employee.calculateYearlySales);
endforeach;
commitTransaction // causes single company.transactionalEvent to be called.
Note: In this example above it would be easy enough to have a manual call to company.recalcTopEmployeeSales or something along those lines. The problem with this approach is there is NO COUPLING between changing the source data and changing the dependant data. This makes it very easy to accidentally update the source data and not the derived, not to mention all the extra work if you happen to add a second derived field.
I want the fact that there is a data dependencies between employee.yearlySales and company.topYearlySales to be encapsulated in the company and employee classes.
What do ya think?
CR
Ok, I've just been dealing with a situation which has prompted me to moot this idea.
Imagine you had a company and employees class. There is a one to many relationship between company and employees.
Employee has an integer yearly sales figure. Company has a integer attribute on it called topEmployeeSales that is a copy of the yearly sales figure for the employee with the largest yearly sales. Imagine this is done for performance reasons (many employees) and that topEmployeeSales is used as a dictionary key.
The question is, how do you ensure the topEmployeeSales is updated correctly in ALL cases AND that you don't do excessive overcalculation of it.
You can update it whenever the yearly sales is set for any employee and when an employee is added or removed, but that involves calculating it each time. This is fine if you change them one at a time, but is silly if you are doing batch updates of employees.
You can have some background process that causes it to be periodically updated but that means it won't be guaranteed correct if read between the employee update and the company update.
An elegant solution would be a mechanism in Jade whereby an object can be flagged as dirty and a special "transactional" method can be called just before the commit transaction. I would envision something similar to a causeEvent call except that it gets called before the transaction is complete.
Then you could calculate the derived fields once and only once per transaction.
it code it might look something like.
employee.setYearlySales(sales : Integer);begin
yearlySales := sales;
myCompany.causeTransactionalEvent(Event_Update_Top_Sales);
end;
company.transactionalEvent(eventType: Integer);begin
if eventType = Event_Update_Top_Sales then
// calculate and store top yearly sales...
endif;
end;
and then you could have
begin
Transaction
foreach employee in company.allEmployees do
employee.setYearlySales(employee.calculateYearlySales);
endforeach;
commitTransaction // causes single company.transactionalEvent to be called.
Note: In this example above it would be easy enough to have a manual call to company.recalcTopEmployeeSales or something along those lines. The problem with this approach is there is NO COUPLING between changing the source data and changing the dependant data. This makes it very easy to accidentally update the source data and not the derived, not to mention all the extra work if you happen to add a second derived field.
I want the fact that there is a data dependencies between employee.yearlySales and company.topYearlySales to be encapsulated in the company and employee classes.
What do ya think?
CR