From d9e3b89ac37e1929c7ae4f014f897b6c6f91249e Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 14 Feb 2006 00:19:22 +0000 Subject: [PATCH] some updates to UOW, fixes to all those relation() calls --- doc/build/content/adv_datamapping.myt | 10 +++---- doc/build/content/datamapping.myt | 42 +++++++++++++-------------- doc/build/content/unitofwork.myt | 25 ++++++++-------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/doc/build/content/adv_datamapping.myt b/doc/build/content/adv_datamapping.myt index 74f09b8ba1..a3c9683e34 100644 --- a/doc/build/content/adv_datamapping.myt +++ b/doc/build/content/adv_datamapping.myt @@ -163,12 +163,12 @@ <&|formatting.myt:code&> # order address objects by address id mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses, order_by=addresses.c.address_id) + 'addresses' : relation(mapper(Address, addresses), order_by=addresses.c.address_id) }) # eager load with ordering - the ORDER BY clauses of parent/child will be organized properly mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses, order_by=desc(addresses.c.email_address), eager=True) + 'addresses' : relation(mapper(Address, addresses), order_by=desc(addresses.c.email_address), eager=True) }, order_by=users.c.user_id) @@ -195,7 +195,7 @@ However, things get tricky when dealing with eager relationships, since a straig class Address(object): pass m = mapper(User, users, properties={ - 'addresses' : relation(Address, addresses, lazy=False) + 'addresses' : relation(mapper(Address, addresses), lazy=False) }) r = m.select(User.c.user_name.like('F%'), limit=20, offset=10) <&|formatting.myt:poppedcode, link="sql" &> @@ -293,7 +293,7 @@ WHERE rowcount.user_id = users.user_id ORDER BY users.oid, addresses.oid # a 'lazy' relationship User.mapper = mapper(User, users, properties = { - 'addreses':relation(Address, addresses, lazy=True) + 'addreses':relation(mapper(Address, addresses), lazy=True) }) # copy the mapper and convert 'addresses' to be eager @@ -415,7 +415,7 @@ WHERE rowcount.user_id = users.user_id ORDER BY users.oid, addresses.oid # mapper two - this one will also eager-load address objects in m2 = mapper(User, users, properties={ - 'addresses' : relation(Address, addresses, lazy=False) + 'addresses' : relation(mapper(Address, addresses), lazy=False) }) # get a user. this user will not have an 'addreses' property diff --git a/doc/build/content/datamapping.myt b/doc/build/content/datamapping.myt index bd4f8dd912..51bdff878d 100644 --- a/doc/build/content/datamapping.myt +++ b/doc/build/content/datamapping.myt @@ -230,23 +230,13 @@ INSERT INTO users (user_name, password) VALUES (:user_name, :password) self.state = state self.zip = zip -

And then a Mapper that will define a relationship of the User and the Address classes to each other as well as their table metadata. We will add an additional mapper keyword argument properties which is a dictionary relating the name of an object property to a database relationship, in this case a relation object which will define a new mapper for the Address class:

+

And then a Mapper that will define a relationship of the User and the Address classes to each other as well as their table metadata. We will add an additional mapper keyword argument properties which is a dictionary relating the name of an object property to a database relationship, in this case a relation object against a newly defined mapper for the Address class:

<&|formatting.myt:code&> User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses) + 'addresses' : relation(mapper(Address, addresses)) } ) -

Alternatively, the Address mapper can be defined separately. This allows the mappers of various objects to be combined in any number of ways at runtime: - <&|formatting.myt:code&> - Address.mapper = mapper(Address, addresses) - User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address.mapper) - } - ) - - -

Lets do some operations with these classes and see what happens:

<&|formatting.myt:code&> @@ -289,7 +279,7 @@ VALUES (:user_id, :street, :city, :state, :zip) <&|formatting.myt:code&> User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses, private=True) + 'addresses' : relation(mapper(Address, addresses), private=True) } ) del u.addresses[1] @@ -310,8 +300,9 @@ DELETE FROM addresses WHERE addresses.address_id = :address_id <&|doclib.myt:item, name="backreferences", description="Useful Feature: Backreferences" &>

By creating relations with the backref keyword, a bi-directional relationship can be created which will keep both ends of the relationship updated automatically, even without any database queries being executed. Below, the User mapper is created with an "addresses" property, and the corresponding Address mapper receives a "backreference" to the User object via the property name "user": <&|formatting.myt:code&> + Address.mapper = mapper(Address, addresses) User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses, backref='user') + 'addresses' : relation(Address.mapper, backref='user') } ) @@ -379,7 +370,7 @@ the name is "pluralized", which currently is based on the English language (i.e. <&|formatting.myt:code&> # define a mapper User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses, private=True) + 'addresses' : relation(mapper(Address, addresses), private=True) }) # select users where username is 'jane', get the first element of the list @@ -447,8 +438,9 @@ ORDER BY users.oid

With just a single parameter "lazy=False" specified to the relation object, the parent and child SQL queries can be joined together. <&|formatting.myt:code&> + Address.mapper = mapper(Address, addresses) User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses, lazy=False) + 'addresses' : relation(Address.mapper, lazy=False) } ) @@ -495,7 +487,7 @@ ORDER BY users.oid, addresses.oid <&|formatting.myt:code&> # user mapper with lazy addresses User.mapper = mapper(User, users, properties = { - 'addresses' : relation(Address, addresses) + 'addresses' : relation(mapper(Address, addresses)) } ) @@ -543,10 +535,13 @@ ORDER BY users.oid, addresses.oid class UserPrefs(object): pass UserPrefs.mapper = mapper(UserPrefs, prefs) - + + # address mapper + Address.mapper = mapper(Address, addresses) + # make a new mapper referencing everything. m = mapper(User, users, properties = dict( - addresses = relation(Address, addresses, lazy=True, private=True), + addresses = relation(Address.mapper, lazy=True, private=True), preferences = relation(UserPrefs.mapper, lazy=False, private=True), )) @@ -718,6 +713,9 @@ INSERT INTO article_keywords (article_id, keyword_id) VALUES (:article_id, :keyw class KeywordAssociation(object): pass + # mapper for KeywordAssociation + KeywordAssociation.mapper = mapper(KeywordAssociation, itemkeywords) + # mappers for Users, Keywords User.mapper = mapper(User, users) Keyword.mapper = mapper(Keyword, keywords) @@ -726,11 +724,11 @@ INSERT INTO article_keywords (article_id, keyword_id) VALUES (:article_id, :keyw # eager loading. but the user who added each keyword, we usually dont need so specify # lazy loading for that. m = mapper(Article, articles, properties=dict( - keywords = relation(KeywordAssociation, itemkeywords, lazy=False, association=Keyword, + keywords = relation(KeywordAssociation.mapper, lazy=False, association=Keyword, primary_key = [itemkeywords.c.article_id, itemkeywords.c.keyword_id], properties={ - 'keyword' : relation(Keyword, lazy = False), - 'user' : relation(User, lazy = True) + 'keyword' : relation(Keyword, lazy = False), # uses primary Keyword mapper + 'user' : relation(User, lazy = True) # uses primary User mapper } ) ) diff --git a/doc/build/content/unitofwork.myt b/doc/build/content/unitofwork.myt index e1c5cf1bce..30e09a5ce1 100644 --- a/doc/build/content/unitofwork.myt +++ b/doc/build/content/unitofwork.myt @@ -16,20 +16,21 @@

<&|doclib.myt:item, name="getting", description="Accessing UnitOfWork Instances" &> -

The current unit of work is a thread-local instance maintained within an object called a Session. These objects are accessed as follows:

+

The current unit of work is accessed via the Session interface. The Session is available in a thread-local context from the objectstore module as follows:

<&|formatting.myt:code&> - # get the current session - there is by default one per application - s = objectstore.session() - - # get the thread local unit of work from the session - u = s.uow + # get the current thread's session + s = objectstore.get_session() -

The Session object acts as a proxy to all attributes on the current thread's unit of work and also includes the common methods begin(), commit(), etc. Also, most methods are available as functions on the objectstore package itself so common operations need not explicitly reference the current Session or UnitOfWork instance. +

The Session object acts as a proxy to an underlying UnitOfWork object. Common methods include commit(), begin(), clear(), and delete(). Most of these methods are available at the module level in the objectstore module, which operate upon the Session returned by the get_session() function.

To clear out the current thread's UnitOfWork, which has the effect of discarding the Identity Map and the lists of all objects that have been modified, just issue a clear:

<&|formatting.myt:code&> + # via module objectstore.clear() + + # or via Session + objectstore.get_session().clear()

This is the easiest way to "start fresh", as in a web application that wants to have a newly loaded graph of objects on each request. Any object instances before the clear operation should be discarded.

@@ -37,13 +38,13 @@

The current thread's UnitOfWork object keeps track of objects that are modified. It maintains the following lists:

<&|formatting.myt:code&> # new objects that were just constructed - objectstore.session().new + objectstore.get_session().new # objects that exist in the database, that were modified - objectstore.session().dirty + objectstore.get_session().dirty # objects that have been marked as deleted via objectstore.delete() - objectstore.session().deleted + objectstore.get_session().deleted

To commit the changes stored in those lists, just issue a commit. This can be called via objectstore.session().commit(), or through the module-level convenience method in the objectstore module:

<&|formatting.myt:code&> @@ -69,7 +70,7 @@ myobj1.foo = "something new" # begin an objectstore scope - # this is equivalent to objectstore.uow().begin() + # this is equivalent to objectstore.get_session().begin() objectstore.begin() # modify another object @@ -215,7 +216,7 @@ r = MyObj.mapper.using(s).select_by(id=12) # get the session that corresponds to an instance - s = objectstore.session(x) + s = objectstore.get_session(x) # commit s.commit() -- 2.47.2