On Tuesday, April 30, 2013 3:42:23 PM UTC+3, Anthony wrote:

> This is nice, but you're still talking about very general features. It 
> would be more helpful if you could explain why we need those features. 
> Perhaps you could show in SQLA how you would specify and interact with a 
> particular data model, and then explain why you think that is better/easier 
> than how you would do it using the DAL.


Well, I propose adding a set of tools for building business-model classes 
on-top of the DAL.
I basically mean implementing a 'Unif-Of-Work', and an 'identity-map' as 
explained in the link(s) I provided.
Now, what does this mean...

Well, here is what it does NOT mean - it should NOT lead the developer to 
implement an Active-Record model.
Class-attributes representing records, should NOT 'save()' whenever you set 
them, and should NOT *automatically* 'load()' whenever you access them.
That said, the developer should also NOT have to manage the 
'order-of-operations' by himself - this should be automated (read: 
"auto-inferred from the schema').

Instead, when an attribute is being set, it should marks itself as 'dirty', 
and would be 'pushed' to the database later.
There should also be a way to tell the class-attributes, which other 
attributes of which other classes would be affected by it being modified 
(SQLA calls it the 'relationship-object').
Then, there should be a procedure that uses this information, and while keeping 
track of what's going on inside the transaction, whenever a record is 
changed somehow, it 'discovers' which other records participating in the 
current transaction, might be effected by that change to that attribute, 
and invalidates their caches.
The idea is that there is a mechanism that makes sure that if there are 
pending-changes of other attributes that needs to be pushed 'before' the 
attribute-being accessed is valid, then the push-operations are executed 
before the attribute refreshes itself. This is done by linking events 
between attributes, and propagating-them on attribute-access (SQLA calls 
this a 'cascade').
** The process of marking relationships may be further automated even 
beyond what exists in SQLA, by analyzing the db-schema itself, and 
'inferring' relationships bi-directionally, and wiring all the events 
automatically at class-instantiation-time.*
If there are no such pending-changes, than the attribute being accessed 
should be assumed to be valid (so it's "caches" value is returned), unless 
it was previously invalidated by a transaction-commit. Every 
transaction-commit should invalidate all existing records that are in 
memory.

This is basically the 'unit-of-work' pattern (if I understood correctly)
** But you should really watch the lectures I posted - they probably 
explain this much better than I did...*

"What are the benefits?" You should ask?

Well, there are performance-improvements with the caching mechanism, and 
with the aggregation of operations - certain change-operations are only 
pushed to the transaction-view, when they are actually needed, or at the 
end of the transaction. There may also be consistency-benefits, by insuring 
correct order-of-operations.
Lastly, the main benefit is automatic-handling of caching and ordering or 
operations, that the developer no-longer needs to take care of himself.
The benefit is not just for simple-data-modes, on the contrary - the more 
complex the data-mode, the more this becomes beneficial, as the 
automatic-detection of relationship-dependencies, and auto-cascade of 
operations, can both save brain-cycles from the developer trying to hold 
the whole schema in his head and make sure he pushes things in the correct 
order, and also prevent human-errors that can mess-up the database in cases 
that constrains are insufficient, and the developer overlooked some 
relationship-dependencies and was using stale-data without knowing it.

Then there is the 'identity-map':
This is a complementary-needed feature, to maintain consistency across 
results of the same records taken in different places in the code within 
the same transaction.
It makes sure that there can be one-and-only-one instance or a record 
in-memory withing a single transaction of a single db-session.

"What are the benefits here?" You ask?

First of all, there's a consistency issue that can arise without such a 
system, if the developer is manually controlling the order-of-operations, 
and makes a mistake.
This is not an issue that is exclusive for Active-Record patterns - it can 
also happen in web2py's DAL.
For example, lets take the following code:

def setItemName(id, name):
    row = db.item[id].select()
    row.update_record(name=name)

def getItemByName(name):
   return db.item(db.item.name==name).select()

id = 42
...
row = db.item[id].select()
row.name='some name' # or row[name]='some name' or row.update(name='some 
name')
... 
def setItemName(id, 'some other name')
....
getItemByName(row.name)

As you can see, the last function-call would either fail, or silently 
return something other than what was asked for.
The reason is that there is no singleton of a record that was given back.
The function that pushed the item's name-change to the database, did not 
affect the row-object that represented that same record outside.

The 'identity-map' solves this by storing all rows received for a given 
transaction, in a thread-local-global variable, and re-uses it
based on it's identity (table-name + field-name + primary-key). This also 
has some memory-benefits, especially for large queries.
** BTW: SQLA-ORM is doing this, Django-ORM is not...*
This feature can be implemented within the DAL itself, but does not have to 
be. As long as the db-connection is paired with a thread-local pool of 
records, and that this pool is invalidated on each commit, things with work 
fine. But it's an obvious-fit for the db-connection object, as it can use 
it as a cache internally, and can invalidate it's pool internally on 
'commit()' calls.

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to