[Sqlalchemy-commits] [1199] sqlalchemy/trunk/doc: doc dev
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-03-25 18:13:38
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1199] sqlalchemy/trunk/doc: doc dev</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1199</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-25 12:13:01 -0600 (Sat, 25 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>doc dev</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkdocbuildcontentunitofworkmyt">sqlalchemy/trunk/doc/build/content/unitofwork.myt</a></li> <li><a href="#sqlalchemytrunkdocbuildlibhighlightpy">sqlalchemy/trunk/doc/build/lib/highlight.py</a></li> <li><a href="#sqlalchemytrunkdocdocscss">sqlalchemy/trunk/doc/docs.css</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkdocbuildcontentunitofworkmyt"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/build/content/unitofwork.myt (1198 => 1199)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/build/content/unitofwork.myt 2006-03-25 17:23:41 UTC (rev 1198) +++ sqlalchemy/trunk/doc/build/content/unitofwork.myt 2006-03-25 18:13:01 UTC (rev 1199) </span><span class="lines">@@ -58,7 +58,7 @@ </span><span class="cx"> </&> </span><span class="cx"> </span><span class="cx"> <&|doclib.myt:item, name="changed", description="Whats Changed ?" &> </span><del>- <p>The next concept is that in addition to the Session storing a record of all objects loaded or saved, it also stores records of all <b>newly created</b> objects, records of all objects whose attributes have been modified, records of all objects that have been marked as deleted, and records of all list-based attributes where additions or deletions have occurred. These lists are used when a <code>commit()</code> call is issued to save all changes. After the commit occurs, these lists are all cleared out.</p> </del><ins>+ <p>The next concept is that in addition to the Session storing a record of all objects loaded or saved, it also stores records of all <b>newly created</b> objects, records of all objects whose attributes have been <b>modified</b>, records of all objects that have been marked as <b>deleted</b>, and records of all <b>modified list-based attributes</b> where additions or deletions have occurred. These lists are used when a <code>commit()</code> call is issued to save all changes. After the commit occurs, these lists are all cleared out.</p> </ins><span class="cx"> </span><span class="cx"> <p>These records are all tracked by a collection of <code>Set</code> objects (which are a SQLAlchemy-specific instance called a <code>HashSet</code>) that are also viewable off the Session:</p> </span><span class="cx"> <&|formatting.myt:code&> </span><span class="lines">@@ -76,64 +76,96 @@ </span><span class="cx"> </&> </span><span class="cx"> <p>Heres an interactive example, assuming the <code>User</code> and <code>Address</code> mapper setup first outlined in <&formatting.myt:link, path="datamapping_relations"&>:</p> </span><span class="cx"> <&|formatting.myt:code&> </span><del>- >>> session = objectstore.get_session() </del><ins>+ ">>>" # get the current thread's session + ">>>" session = objectstore.get_session() </ins><span class="cx"> </span><del>- >>> u = User(user_name='Fred') - >>> u.addresses.append(Address(city='New York')) - >>> u.addresses.append(Address(city='Boston')) </del><ins>+ ">>>" # create a new object, with a list-based attribute + ">>>" # containing two more new objects + ">>>" u = User(user_name='Fred') + ">>>" u.addresses.append(Address(city='New York')) + ">>>" u.addresses.append(Address(city='Boston')) </ins><span class="cx"> </span><del>- >>> session.new - [<__main__.User object at 0x713630>, <__main__.Address object at 0x713a70>, <__main__.Address object at 0x713b30>] </del><ins>+ ">>>" # objects are in the "new" list + ">>>" session.new + [<__main__.User object at 0x713630>, + <__main__.Address object at 0x713a70>, + <__main__.Address object at 0x713b30>] </ins><span class="cx"> </span><del>- >>> # view the "modified lists" member, reveals our two Address objects as well - >>> session.modified_lists </del><ins>+ ">>>" # view the "modified lists" member, + ">>>" # reveals our two Address objects as well, inside of a list + ">>>" session.modified_lists </ins><span class="cx"> [[<__main__.Address object at 0x713a70>, <__main__.Address object at 0x713b30>]] </span><span class="cx"> </span><del>- >>> # lets view what the class/ID is for the list objects - >>> ["%s %s" % (l.__class__, id(l)) for l in session.modified_lists] </del><ins>+ ">>>" # lets view what the class/ID is for the list object + ">>>" ["%s %s" % (l.__class__, id(l)) for l in session.modified_lists] </ins><span class="cx"> ['sqlalchemy.mapping.unitofwork.UOWListElement 7391872'] </span><span class="cx"> </span><del>- >>> # now commit - >>> session.commit() </del><ins>+ ">>>" # now commit + ">>>" session.commit() </ins><span class="cx"> </span><del>- >>> # new list is blank - >>> session.new </del><ins>+ ">>>" # the "new" list is now empty + ">>>" session.new </ins><span class="cx"> [] </span><del>- >>> # modified lists is blank - >>> session.modified_lists </del><ins>+ + ">>>" # the "modified lists" list is now empty + ">>>" session.modified_lists </ins><span class="cx"> [] </span><span class="cx"> </span><del>- >>> # now lets modify an object - >>> u.user_name='Ed' </del><ins>+ ">>>" # now lets modify an object + ">>>" u.user_name='Ed' </ins><span class="cx"> </span><del>- >>> # it gets placed in "dirty" - >>> session.dirty </del><ins>+ ">>>" # it gets placed in the "dirty" list + ">>>" session.dirty </ins><span class="cx"> [<__main__.User object at 0x713630>] </span><span class="cx"> </span><del>- >>> # delete one of the addresses - >>> session.delete(u.addresses[0]) - >>> # and also delete it off the User object, note that this is not automatic - >>> del u.addresses[0] - >>> session.deleted </del><ins>+ ">>>" # delete one of the addresses + ">>>" session.delete(u.addresses[0]) + + ">>>" # and also delete it off the User object, note that + ">>>" # this is *not automatic* when using session.delete() + ">>>" del u.addresses[0] + ">>>" session.deleted </ins><span class="cx"> [<__main__.Address object at 0x713a70>] </span><span class="cx"> </span><del>- >>> # commit - >>> session.commit() </del><ins>+ ">>>" # commit + ">>>" session.commit() </ins><span class="cx"> </span><del>- >>> # all lists are cleared out - >>> session.new, session.dirty, session.modified_lists, session.deleted </del><ins>+ ">>>" # all lists are cleared out + ">>>" session.new, session.dirty, session.modified_lists, session.deleted </ins><span class="cx"> ([], [], [], []) </span><span class="cx"> </span><del>- >>> #identity map has the User and the one remaining Address - >>> session.identity_map.values() </del><ins>+ ">>>" # identity map has the User and the one remaining Address + ">>>" session.identity_map.values() </ins><span class="cx"> [<__main__.Address object at 0x713b30>, <__main__.User object at 0x713630>] </span><span class="cx"> </&> </span><ins>+ <p>Unlike the identity map, the <code>new</code>, <code>dirty</code>, <code>modified_lists</code>, and <code>deleted</code> lists are <b>not weak referencing.</b> This means if you abandon all references to new or modified objects within a session, <b>they are still present</b> and will be saved on the next commit operation, unless they are removed from the Session explicitly (more on that later). The <code>new</code> list may change in a future release to be weak-referencing, however for the <code>deleted</code> list, one can see that its quite natural for a an object marked as deleted to have no references in the application, yet a DELETE operation is still required.</p> </ins><span class="cx"> </&> </span><span class="cx"> </span><span class="cx"> <&|doclib.myt:item, name="commit", description="Commit" &> </span><del>- <p>This is the main gateway to what the Unit of Work does best, which is save everything ! </del><ins>+ <p>This is the main gateway to what the Unit of Work does best, which is save everything ! It should be clear by now that a commit looks like: </ins><span class="cx"> </p> </span><ins>+ <&|formatting.myt:code&> + objectstore.get_session().commit() </ins><span class="cx"> </&> </span><ins>+ <p>It also can be called with a list of objects; in this form, the commit operation will be limited only to the objects specified in the list, as well as any child objects within <code>private</code> relationships for a delete operation:</p> + <&|formatting.myt:code&> + # saves only user1 and address2. all other modified + # objects remain present in the session. + objectstore.get_session().commit(user1, address2) + </&> + <p>This second form of commit should be used more carefully as it will not necessarily locate other dependent objects within the session, whose database representation may have foreign constraint relationships with the objects being operated upon.</p> + + <&|doclib.myt:item, name="whatis", description="What Commit is, and Isn't" &> + <p>The purpose of the Commit operation is to instruct the Unit of Work to analyze its lists of modified objects, assemble them into a dependency graph, and fire off the appopriate INSERT, UPDATE, and DELETE statements via the mappers related to those objects. <b>And thats it.</b> This means, it is not going to change anything about your objects as they exist in memory, with the exception of populating scalar object attributes with newly generated default column values which normally only involves primary and foreign key identifiers. A brief list of what will <b>not</b> happen includes:</p> + <ul> + <li>It will not append or delete any items from any list-based attributes. Any objects that have been inserted or deleted will be updated as such in the database, but if a deleted object instance is still attached to a parent object, it will remain.</li> + <li>It will not set or remove any scalar object attributes, even if the database identifier columns have been committed. This means, if you set <code>user.address_id</code> to 5, that will be saved, but it will not place an <code>Address</code> object on the <code>user</code> object. Similarly, if the <code>Address</code> object is deleted but is still attached to the <code>User</code>, it will remain.</li> + </ul> + <P>So the primary guideline for dealing with commit() is, <b>the developer is responsible for maintaining the objects in memory, the unit of work is responsible for maintaining the database representation.</b></p> + + <p>A terrific feature of SQLAlchemy which is also a supreme source of confusion is the backreference feature, described in <&formatting.myt:link, path="datamapping_relations_backreferences"&>. This feature allows two types of objects to maintain attributes that reference each other, typically one object maintaining a list of elements of the other side. When you append an element to the list, the element gets a "backreference" back to the object which has the list. When you attach the list-holding element to the child element, the child element gets attached to the list. <b>This feature has nothing to do whatsoever with the Unit of Work.</b> It is strictly a small convenience feature added to support an extremely common pattern. Besides this one little feature, <b>the developer must maintain in-memory object relationships manually</b>. Note that we are talking about the <b>manipulation</b! > of objects, not the initial loading of them which is handled by the mapper.</p> + </&> + </&> </ins><span class="cx"> </span><span class="cx"> <&|doclib.myt:item, name="delete", description="Delete" &> </span><span class="cx"> </&> </span></span></pre></div> <a id="sqlalchemytrunkdocbuildlibhighlightpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/build/lib/highlight.py (1198 => 1199)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/build/lib/highlight.py 2006-03-25 17:23:41 UTC (rev 1198) +++ sqlalchemy/trunk/doc/build/lib/highlight.py 2006-03-25 18:13:01 UTC (rev 1199) </span><span class="lines">@@ -176,7 +176,13 @@ </span><span class="cx"> curstyle = self.get_style(t[0], t[1]) </span><span class="cx"> </span><span class="cx"> (start, end) = self._line_grid(line, t[2], t[3]) </span><del>- tokens.append(line[start[1]:end[1]]) </del><ins>+ text = line[start[1]:end[1]] + + # special hardcoded rule to allow "interactive" demos without + # >>> getting sucked in as >> , > operators + if text == '">>>"': + text = '>>>' + tokens.append(text) </ins><span class="cx"> curc = t[3][1] </span><span class="cx"> curl = t[3][0] </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunkdocdocscss"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/docs.css (1198 => 1199)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/docs.css 2006-03-25 17:23:41 UTC (rev 1198) +++ sqlalchemy/trunk/doc/docs.css 2006-03-25 18:13:01 UTC (rev 1199) </span><span class="lines">@@ -96,6 +96,9 @@ </span><span class="cx"> font-size:12px; </span><span class="cx"> } </span><span class="cx"> </span><ins>+pre { + overflow:auto; +} </ins><span class="cx"> .codeline { </span><span class="cx"> font-family:courier, serif; </span><span class="cx"> font-size:12px; </span></span></pre> </div> </div> </body> </html> |