]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
some updates to UOW, fixes to all those relation() calls
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Feb 2006 00:19:22 +0000 (00:19 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Feb 2006 00:19:22 +0000 (00:19 +0000)
doc/build/content/adv_datamapping.myt
doc/build/content/datamapping.myt
doc/build/content/unitofwork.myt

index 74f09b8ba11135cf901152ba0c3f35966aac500a..a3c9683e3413a62a03f71db52a24a98ebae0b1a0 100644 (file)
 <&|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
index bd4f8dd912c963783d8d866d7552e44b6f2b5fe9..51bdff878dd3d73ca89d61ce43e2fb19c7a7dd7c 100644 (file)
@@ -230,23 +230,13 @@ INSERT INTO users (user_name, password) VALUES (:user_name, :password)
                     self.state = state
                     self.zip = zip
         </&>
-<p>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 <span class="codeline">properties</span> which is a dictionary relating the name of an object property to a database relationship, in this case a <span class="codeline">relation</span> object which will define a new mapper for the Address class:</p>
+<p>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 <span class="codeline">properties</span> which is a dictionary relating the name of an object property to a database relationship, in this case a <span class="codeline">relation</span> object against a newly defined  mapper for the Address class:</p>
         <&|formatting.myt:code&>
             User.mapper = mapper(User, users, properties = {
-                                'addresses' : relation(Address, addresses)
+                                'addresses' : relation(mapper(Address, addresses))
                             }
                           )
         </&>
-<p>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)
-                            }
-                          )
-        </&>
-
-</p>
 <p>Lets do some operations with these classes and see what happens:</p>
 
         <&|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" &>
 <p>By creating relations with the <span class="codeline">backref</span> 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
         <p>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
                     }
                 )
                 )
index e1c5cf1bce7f334a30b52f7b80fbd77fb2b603d4..30e09a5ce12a929fa102ee3b6b90cee69619ce41 100644 (file)
     </ul></p>
     </&>
     <&|doclib.myt:item, name="getting", description="Accessing UnitOfWork Instances" &>
-    <p>The current unit of work is a thread-local instance maintained within an object called a Session.  These objects are accessed as follows:</p>
+    <p>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:</p>
         <&|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()
         </&>
-    <p>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.
+    <p>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.
     </p>
     <p>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:
     </p>
     <&|formatting.myt:code&>
+        # via module
         objectstore.clear()
+        
+        # or via Session
+        objectstore.get_session().clear()
     </&>
     <p>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.</p>
     </&>
     <p>The current thread's UnitOfWork object keeps track of objects that are modified.  It maintains the following lists:</p>
     <&|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
     </&>
     <p>To commit the changes stored in those lists, just issue a commit.  This can be called via <span class="codeline">objectstore.session().commit()</span>, or through the module-level convenience method in the objectstore module:</p>
     <&|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
         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()