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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.