From: Luke O. <lu...@me...> - 2003-04-25 22:10:43
|
Hey all - Ok, I'm going to present a possibly controversial idea. I'd like to propose the concept of 'temporary' objects, for use in cases where you want to save values (say from a series of web forms) in SQLObject-constrained containers (columns, relationships), but don't want to persist to the database until the user finishes the process. Two use cases: 1. Creating a new temp object, modifying etc, eventually persisting to a real SQLObject. 2. Taking an existing SQLObject, creating a temp from it, modifying etc, and storing back to the original record. Hardest part of this: dealing with foreignKeys, on persist keys have to be updated from their fake values to the actual new objects' ids. Not sure whether to implement this as a helper class to SQLObject (that takes an SQLObject on init), or directly in SQLObject. Examples: Helper class ------------ x = TempSQLObject.new(Person,....) #just like SQLOBject.new(....) x.whatever ... y = x.persist() # y is now a real SQLObject of type Person. z = Person(23) # existing object w = TempSQLObject(z) .... z = w.persist() Part of SQLObject ----------------- x = Person.temp(.....) # just like .new() .... x.persist() # no possibility of keeping temp object; it's real now. y = Person(23) w = y.temp() .... y.persist(w) # or y.set(w) ? Any thoughts? My immediate preference is to do it as part of SQLObject, it would be very similar to the _SO_autoInitDone flags. But makes a rather substantial change to the class for something that other people may not need. The TempSQLObject direction keeps more separation, but makes interface maintenance more difficult (in my mind so far). Enjoy, Luke |
From: Brad B. <br...@bb...> - 2003-04-26 16:02:55
|
On 04/25/03 16:56, Luke Opperman wrote: > Hey all - > > Ok, I'm going to present a possibly controversial idea. I'd like to > propose the concept of 'temporary' objects, for use in cases where > you want to save values (say from a series of web forms) in > SQLObject-constrained containers (columns, relationships), but don't > want to persist to the database until the user finishes the process. > > Two use cases: 1. Creating a new temp object, modifying etc, > eventually persisting to a real SQLObject. 2. Taking an existing > SQLObject, creating a temp from it, modifying etc, and storing back > to the original record. > > Hardest part of this: dealing with foreignKeys, on persist keys have > to be updated from their fake values to the actual new objects' ids. > > Not sure whether to implement this as a helper class to SQLObject > (that takes an SQLObject on init), or directly in SQLObject. > Examples: > > > Helper class > ------------ > x = TempSQLObject.new(Person,....) #just like SQLOBject.new(....) > x.whatever > ... > y = x.persist() # y is now a real SQLObject of type Person. > > > z = Person(23) # existing object > w = TempSQLObject(z) > .... > z = w.persist() > > > Part of SQLObject > ----------------- > x = Person.temp(.....) # just like .new() > .... > x.persist() # no possibility of keeping temp object; it's real now. > > y = Person(23) > w = y.temp() > .... > y.persist(w) # or y.set(w) ? > > > Any thoughts? My immediate preference is to do it as part of > SQLObject, it would be very similar to the _SO_autoInitDone flags. > But makes a rather substantial change to the class for something that > other people may not need. The TempSQLObject direction keeps more > separation, but makes interface maintenance more difficult (in my > mind so far). Your motives are well-founded, but I don't entirely agree with your choice of metaphor. What you're really looking for is transactions. Something like: from Transaction import Transaction from invoicing import Client t = Transaction() c = Client(1) t.insertObject(c) c.address1 = "100 New Street" c.telephone = 4045551212 c.fax = 4045551213 t.saveChanges() the you can do things like: from Transaction import Transaction from invoicing import Client t = Transaction() c = Client(1) t.insertObject(c) c.address1 = "100 New Street" try: c.telephone = 40455519 except TelephoneErr, err: print "Error saving telephone number:", err.value t.rollback() else: t.commit() This kind of interface would not care about whether the backend persistence is a database, or merely simple files and would provide the kind of atomicity you're looking for, in a more "classical" database style. What do you think? -- Brad Bollenbach BBnet.ca |
From: Luke O. <lu...@me...> - 2003-04-26 18:45:03
|
Yes, you're right, I did end up asking for a transaction-like concept. Hmm. The challenge remains about the same to implement this across SQLObject, but I think your metaphor/example is right on. I'm wondering whether to rely on database-implemented transactions if possible, or whether to implement it regardless across SQLObject. But now I need to think. - Luke > Your motives are well-founded, but I don't entirely agree with your > choice of metaphor. > > What you're really looking for is transactions. > > Something like: > > from Transaction import Transaction > from invoicing import Client > > t = Transaction() > c = Client(1) > t.insertObject(c) > c.address1 = "100 New Street" > c.telephone = 4045551212 > c.fax = 4045551213 > t.saveChanges() > > the you can do things like: > > from Transaction import Transaction > from invoicing import Client > > t = Transaction() > c = Client(1) > t.insertObject(c) > c.address1 = "100 New Street" > > try: > c.telephone = 40455519 > except TelephoneErr, err: > print "Error saving telephone number:", err.value > t.rollback() > else: > t.commit() > > This kind of interface would not care about whether the backend > persistence is a database, or merely simple files and would provide > the kind of atomicity you're looking for, in a more "classical" > database style. > > What do you think? > > -- > Brad Bollenbach > BBnet.ca > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > sqlobject-discuss mailing list > sql...@li... > https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss > -- i find your contempt for naked feet curious. |
From: Nick <ni...@dd...> - 2003-04-26 17:49:22
|
Hi, I'm new to the project, but I've been working on a project that is so similar for the past 2 years (since Python 2.2a1) that it's fairly spooky. I mean, the classes are even named and organized almost exactly the same. However, my recent ex-employer owns the code, so this is the perfect opportunity to continue working on it. On Sat, 2003-04-26 at 11:01, Brad Bollenbach wrote: > On 04/25/03 16:56, Luke Opperman wrote: > > Hey all - > > > > Ok, I'm going to present a possibly controversial idea. I'd like to > > propose the concept of 'temporary' objects, for use in cases where > > you want to save values (say from a series of web forms) in > > SQLObject-constrained containers (columns, relationships), but don't > > want to persist to the database until the user finishes the process. > > Your motives are well-founded, but I don't entirely agree with your > choice of metaphor. > > What you're really looking for is transactions. Right on, that's what I did with my code. What I did was never run any queries and keep a pool of "dirty" object to commit when a commit() call was made, and rollback() would reset to original values. new()s and delete(s) obviously can't be done this way or it will screw up subsequent queries, so the DBIs transaction model was used in addition to the pool. It worked really well. Obviously, this would require somewhat of a change in the DBConnector class (first and foremost removing conn.commit() after each query :), but since there's a fairly complete caching mechanism it's only a matter of marking objects as dirty when modifications are made and then checking the cache and running an update() on every dirty object. Nick |
From: Ian B. <ia...@co...> - 2003-04-29 09:02:09
|
On Fri, 2003-04-25 at 16:56, Luke Opperman wrote: > Ok, I'm going to present a possibly controversial idea. I'd like to > propose the concept of 'temporary' objects, for use in cases where > you want to save values (say from a series of web forms) in > SQLObject-constrained containers (columns, relationships), but don't > want to persist to the database until the user finishes the process. > > Two use cases: 1. Creating a new temp object, modifying etc, > eventually persisting to a real SQLObject. 2. Taking an existing > SQLObject, creating a temp from it, modifying etc, and storing back > to the original record. Yes, I can see the utility. I was just doing a project (without SQLObject) that involved a database, and doing updates and preview, which would be a pain without temporary objects, so I'm sensitive to the need. A lot of ORMs deal with this by having a distinction between the store and the object. You create the object, then add it to the store at some point. There may also be an explicit way to save the object. Both handle the problem, though without any help regarding foreign keys. But that's a whole different metaphor from SQLObject, and not one I care for. So, I'm thinking about how that would otherwise work... and I'm just not seeing it. One way would be to use a different store, like: tmpConn = TempConnection(__connection__) p = Person.new(..., connection=tmpConn) # or... p2 = Person(5, connection=tmpConn) # tmpConn fetches from the database, but doesn't save back to it # so you do stuff with these objects, then... tmpConn.commit() Is that a lame interface? It seems fairly functional, and I can imagine how it would be implemented, even if connection doesn't seem like the right term... but that's the way database transactions are already handled, so I guess it's not so bad. It still leaves the question of IDs of objects that haven't yet been added to the database. > Any thoughts? My immediate preference is to do it as part of > SQLObject, it would be very similar to the _SO_autoInitDone flags. > But makes a rather substantial change to the class for something that > other people may not need. The TempSQLObject direction keeps more > separation, but makes interface maintenance more difficult (in my > mind so far). BTW, _SO_autoInitDone is gone, since objects aren't lazily fetched anymore (since I wasn't coming up with any use cases). I'd be interested in adding this to SQLObject itself, so long as it doesn't mean horribly ugly hacks. There aren't that many hacks in it, and I'm hoping to keep it that way :) Ian |
From: Ian B. <ia...@co...> - 2003-04-29 09:12:18
|
On Sat, 2003-04-26 at 12:48, Nick wrote: > I'm new to the project, but I've been working on a project that is so > similar for the past 2 years (since Python 2.2a1) that it's fairly > spooky. I mean, the classes are even named and organized almost exactly > the same. It's because I'm inside your head! > On Sat, 2003-04-26 at 11:01, Brad Bollenbach wrote: > > On 04/25/03 16:56, Luke Opperman wrote: > > > Hey all - > > > > > > Ok, I'm going to present a possibly controversial idea. I'd like to > > > propose the concept of 'temporary' objects, for use in cases where > > > you want to save values (say from a series of web forms) in > > > SQLObject-constrained containers (columns, relationships), but don't > > > want to persist to the database until the user finishes the process. > > > > Your motives are well-founded, but I don't entirely agree with your > > choice of metaphor. > > > > What you're really looking for is transactions. > > Right on, that's what I did with my code. What I did was never run any > queries and keep a pool of "dirty" object to commit when a commit() call > was made, and rollback() would reset to original values. new()s and > delete(s) obviously can't be done this way or it will screw up > subsequent queries, so the DBIs transaction model was used in addition > to the pool. It worked really well. That seems confusing to me. If you're going to use database transactions, why not just use them entirely? You only seem to really gain something if you can avoid them entirely (and thus make it possible to add transactions to lesser databases). You could keep everything in memory if you could pre-allocate IDs for the new objects, which is kind of interesting -- if you throw the object away, you've only lost some numbers, and numbers are cheap (103493, 10943, 23943 -- see, so cheap I can throw them away!). Stupid MySQL doesn't even have sequences, though, which makes this possibility difficult. I'm okay with deletes not being transactional (outside of using database transactions). I'm not sure I see as much of a use case for that. > Obviously, this would require somewhat of a change in the DBConnector > class (first and foremost removing conn.commit() after each query :), Huh... I wonder why I put that commit in? > but since there's a fairly complete caching mechanism it's only a matter > of marking objects as dirty when modifications are made and then > checking the cache and running an update() on every dirty object. Certainly a database connection could be lazy and not do the update when it was asked (but just remember to do it later). But the idea of just having one database connection type that did this is growing on me. Ian |
From: Nick <ni...@dd...> - 2003-04-29 16:23:55
|
On Tue, 2003-04-29 at 04:13, Ian Bicking wrote: > That seems confusing to me. If you're going to use database > transactions, why not just use them entirely? You only seem to really > gain something if you can avoid them entirely (and thus make it possible > to add transactions to lesser databases). The point there is so that you can roll back an individual object rather than the entire transaction, if desired. Plus, you're not performing any communication to the database, until it's completely necessary. Important for web services and applications, where you can send your content so the user can see response while you do all your db writes at the end. > You could keep everything in memory if you could pre-allocate IDs for > the new objects, which is kind of interesting -- if you throw the object > away, you've only lost some numbers, and numbers are cheap (103493, > 10943, 23943 -- see, so cheap I can throw them away!). Stupid MySQL > doesn't even have sequences, though, which makes this possibility > difficult. > > I'm okay with deletes not being transactional (outside of using database > transactions). I'm not sure I see as much of a use case for that The reason you would actually want to make the queries inside a transaction for inserts and deletes is because you would want the results to show up in subsequent selects. On inserts, you certainly wouldn't see new rows if they weren't sent to the db in a transactions. Now that I think about it, you *can* manage deletes I suppose by checking the cache to see if the row had been deleted and then neglect to return it in the resulting list. > > but since there's a fairly complete caching mechanism it's only a matter > > of marking objects as dirty when modifications are made and then > > checking the cache and running an update() on every dirty object. > > Certainly a database connection could be lazy and not do the update when > it was asked (but just remember to do it later). The reason I think something like that is so important is for web based transactions (which I assume is what started this thread). If your script fails for some reason, you (usually) want to roll back the entire transaction. Which brings me to a question... is it possible to clear out the entire object cache so you can maintain a persistant connection over several web requests? Nick |
From: Ian B. <ia...@co...> - 2003-04-29 20:51:44
|
On Tue, 2003-04-29 at 11:23, Nick wrote: > The reason I think something like that is so important is for web based > transactions (which I assume is what started this thread). If your > script fails for some reason, you (usually) want to roll back the entire > transaction. Which brings me to a question... is it possible to clear > out the entire object cache so you can maintain a persistant connection > over several web requests? If you pass a connection in to the constructor, then that connection's cache is used (not a global cache). So when the connection goes away, so does the cache. Ian |
From: Brad B. <br...@bb...> - 2003-04-29 16:55:42
|
On 04/29/03 04:13, Ian Bicking wrote: > On Sat, 2003-04-26 at 12:48, Nick wrote: > > I'm new to the project, but I've been working on a project that is so > > similar for the past 2 years (since Python 2.2a1) that it's fairly > > spooky. I mean, the classes are even named and organized almost exactly > > the same. > > It's because I'm inside your head! > > > On Sat, 2003-04-26 at 11:01, Brad Bollenbach wrote: > > > On 04/25/03 16:56, Luke Opperman wrote: > > > > Hey all - > > > > > > > > Ok, I'm going to present a possibly controversial idea. I'd like to > > > > propose the concept of 'temporary' objects, for use in cases where > > > > you want to save values (say from a series of web forms) in > > > > SQLObject-constrained containers (columns, relationships), but don't > > > > want to persist to the database until the user finishes the process. > > > > > > Your motives are well-founded, but I don't entirely agree with your > > > choice of metaphor. > > > > > > What you're really looking for is transactions. > > > > Right on, that's what I did with my code. What I did was never run any > > queries and keep a pool of "dirty" object to commit when a commit() call > > was made, and rollback() would reset to original values. new()s and > > delete(s) obviously can't be done this way or it will screw up > > subsequent queries, so the DBIs transaction model was used in addition > > to the pool. It worked really well. > > That seems confusing to me. If you're going to use database > transactions, why not just use them entirely? You only seem to really > gain something if you can avoid them entirely (and thus make it possible > to add transactions to lesser databases). To be useable with database backends that don't support transactions natively, and to provide a consistent interface for using them either way. -- Brad Bollenbach BBnet.ca |
From: Ian B. <ia...@co...> - 2003-04-29 20:55:34
|
On Tue, 2003-04-29 at 11:53, Brad Bollenbach wrote: > > That seems confusing to me. If you're going to use database > > transactions, why not just use them entirely? You only seem to really > > gain something if you can avoid them entirely (and thus make it possible > > to add transactions to lesser databases). > > To be useable with database backends that don't support transactions > natively, and to provide a consistent interface for using them either > way. If we can create in-Python transactions, that'd be great... but if we create something that's in Python, but still depends on database transactions (and so isn't usable from MySQL), then I'm not clear what the advantage is. Ian |
From: Luke O. <lu...@me...> - 2003-04-29 17:30:56
|
Ok, here's my current thoughts on TempObjects/Transactions: First, whether the external interface is a Transaction object that you add objects to or not (Brad's suggestion): > from Transaction import Transaction > from invoicing import Client > t = Transaction() > c = Client(1) > t.insertObject(c) > c.address1 = "100 New Street" > t.saveChanges() ... it seems to me the changes to SQLObject are still the same as my initial suggestions (Object.temp(), Object.persist()): ie, t.insertObject(c) needs to call something equivalent to c.temp() so that it no longer does updates, and t.saveChanges() needs to call c.persist(). Also, i've seen very little suggestion for an alternate way to make a Temp *new* object within a Transaction. You need to a way to specify "create a temp object" as opposed to "create an object then add it to this Transaction". In general new objects make things much messier, with the issue of fake IDs needing to updated when persisted/committed. Again, this is regardless of whether the metaphor is transactions or tempobjects. I am in complete agreement with Ian over "Stores" vs "Objects". I don't want stores; this biases my thoughts on Transaction objects, as they are explicit temporary stores. Now, an also seemingly functionally equivalent would be Ian's TempConnection idea, although I'm not sure I like the interface/look of needing to pass in an alternate connection for each tempobject. In general, I want tempobjects to be created and used just like they were a regular SQLObject, except that they need to be persisted/committed. However, I think this might be a clean *internal* implementation for my concept of temp objects: when an object becomes temp (added to a transaction, or explicitly), it just swaps it's connection for a TempConnection. Hmm.... So here's my plan of action: implement .temp() and .persist() (I'll call it .commit() if it makes people happier :) within SQLObject. This will allow the concept of transactions to be implemented completely independent of database support, if so desired. Semantics: 1. temporary versions of an SQLObject will not be visible to any other connection (ie, unless you have a python-side reference to the object, it doesn't exist.) 2. temporary versions of an SQLObject can reference either other temp objects or real objects. Joins queried on a temp object will return possibly a mix of real and fake objects. The question here is, do we return temp versions of the real objects? tempPerson.employees, do something with the employee objects, presumably (from a transaction perspective) those changes are only saved if the tempPerson is saved... getting messy.... 3. this leads to: real objects can never reference a temp object without becoming temp themselves. I think this is the way to go, but it leads to the final mess 4. does persisting any object persist all temp objects it touches? This makes sense from the example above: create a tempPerson, start adding temp employees to it, I'd like to simply persist tempPerson and have it handle the rest. but does it work the other way (persist one of the employees, and the whole tree/graph is persisted)? Should there be an alternate way to persist just one? (In the context of a transaction this becomes particularily important: when do things I didn't explicitly add to the transaction but that are changed via join/FK get persisted?) That's enough thoughts for now. I'd appreciate comments, but I think it just need to implement something and see how it plays.. - Luke |
From: Ian B. <ia...@co...> - 2003-04-29 20:54:25
|
On Tue, 2003-04-29 at 12:17, Luke Opperman wrote: [snip] > Now, an also seemingly functionally equivalent would be Ian's > TempConnection idea, although I'm not sure I like the interface/look > of needing to pass in an alternate connection for each tempobject. In > general, I want tempobjects to be created and used just like they > were a regular SQLObject, except that they need to be > persisted/committed. However, I think this might be a clean > *internal* implementation for my concept of temp objects: when an > object becomes temp (added to a transaction, or explicitly), it just > swaps it's connection for a TempConnection. Hmm.... TempConnection uses the same interface you'd use for database transactions (which I haven't really tried... but in theory that's how you'd do database transactions). I think, at least, that both these should have the same interface. But when I think more about it, it's just so damn difficult... is this really that much better than a database transaction? I mean, maybe it's possible to get this kind of working, but I suspect it will be a crippled version of the functionality you'd normally have available. > That's enough thoughts for now. I'd appreciate comments, but I think > it just need to implement something and see how it plays.. That's probably a good idea... the issue will probably become much clearer that way. Ian |
From: Paul C. <pa...@pa...> - 2003-04-30 03:57:25
|
On Tuesday, April 29, 2003, at 01:17 PM, Luke Opperman wrote: > > 4. does persisting any object persist all temp objects it touches? > This makes sense from the example above: create a tempPerson, start > adding temp employees to it, I'd like to simply persist tempPerson > and have it handle the rest. but does it work the other way (persist > one of the employees, and the whole tree/graph is persisted)? Should > there be an alternate way to persist just one? (In the context of a > transaction this becomes particularily important: when do things I > didn't explicitly add to the transaction but that are changed via > join/FK get persisted?) > Although I am just an interested observer here I would say that I am slightly concerned that this proposal may add significant complexity to support what I believe to be a marginal set of cases. I believe that the simplicity and cleanness of the SQLObject interface and orthogonality with the underlying database functionality is a strong selling point. In particular delegating the 'hard' transactional aspects to the database (effectively ignoring them at the ORM layer) and where necessary requiring the object to sync with the database (by turning _cacheValues off) strikes me as a pragmatic choice particularly for web applications where concurrent access is required (though possibly pessimistic in some scenarios) Trying to build a generic object store capable of persisting an arbitrary object graphs in a coherent/transactional manner together seems to be excessive and probably impossible if you are trying to support concurrent access from multiple processes (without implementing coherent distributed faulting). PaulC |
From: Nick <ni...@dd...> - 2003-04-30 04:59:19
|
On Tue, 2003-04-29 at 22:57, Paul Chakravarti wrote: > Although I am just an interested observer here I would say that I am > slightly concerned that this proposal may add significant complexity to > support what I believe to be a marginal set of cases. While think there needs to be some kind of transactional capability intrinsic to SQLObject beyound those provided by the DB API, I agree that this looks a bit complex for a simple concept. > I believe that the simplicity and cleanness of the SQLObject interface > and orthogonality with the underlying database functionality is a > strong selling point. Definitely. There are similar projects out there, like Modeling, that can cover *every single case*. I like the KISS principle, myself. The big feature of SQLObject in my mind (and what drew me to this kind of project) is RAD. > Trying to build a generic object store capable of persisting an > arbitrary object graphs in a coherent/transactional manner together > seems to be excessive and probably impossible if you are trying to > support concurrent access from multiple processes (without implementing > coherent distributed faulting). I agree... I advocate some kind of system where you can either cache everything up in a transaction-like manner in a pythonic way until you call commit, or else an autocommit model like it currently uses. That will cover 99% of your users and maintains the simplicity of the interface. Nick |
From: Brad B. <br...@bb...> - 2003-04-30 13:17:33
|
On 04/29/03 23:57, Paul Chakravarti wrote: > > On Tuesday, April 29, 2003, at 01:17 PM, Luke Opperman wrote: > > > >4. does persisting any object persist all temp objects it touches? > >This makes sense from the example above: create a tempPerson, start > >adding temp employees to it, I'd like to simply persist tempPerson > >and have it handle the rest. but does it work the other way (persist > >one of the employees, and the whole tree/graph is persisted)? Should > >there be an alternate way to persist just one? (In the context of a > >transaction this becomes particularily important: when do things I > >didn't explicitly add to the transaction but that are changed via > >join/FK get persisted?) > > > > Although I am just an interested observer here I would say that I am > slightly concerned that this proposal may add significant complexity to > support what I believe to be a marginal set of cases. The more iterations through my brain this discussion makes, the more I lean towards thinking that SQLObject should leave its transaction support as is. I've used many of these frameworks, in both Perl and Python: Modeling, Class::DBI, took a look at MiddleKit and finally SQLObject. What drew me to this framework to begin with was the relatively flat learning curve. I hope we keep it that way. -- Brad Bollenbach BBnet.ca |
From: Ian B. <ia...@co...> - 2003-04-29 22:14:44
|
On Tue, 2003-04-29 at 12:17, Luke Opperman wrote: > > from Transaction import Transaction > > from invoicing import Client > > t = Transaction() > > c = Client(1) > > t.insertObject(c) > > c.address1 = "100 New Street" > > t.saveChanges() I think t.insertObject(c) isn't a good idea. Client(1) is an object that may be in use in several places, and is presumed to be transparently persistent. When you put it into the transaction you've made temporary for all users of the object. Bad bugs will follow. At least in threaded situations. This is why I think the object has to be instantiated as part of the transaction, or perhaps copied if you don't like instantiation... t = Transaction() c = Client(1) ctmp = c.inTransaction(t) # or... ctmp = Client(1, t) Ian |
From: Luke O. <lu...@me...> - 2003-04-29 22:56:28
|
> I think t.insertObject(c) isn't a good idea. Client(1) is an > object > that may be in use in several places, and is presumed to be > transparently persistent. When you put it into the transaction > you've > made temporary for all users of the object. Bad bugs will follow. > At > least in threaded situations. > > This is why I think the object has to be instantiated as part of > the > transaction, or perhaps copied if you don't like instantiation... > > t = Transaction() > c = Client(1) > ctmp = c.inTransaction(t) > # or... > ctmp = Client(1, t) > > Ian > I couldn't agree more, this is also refers to the challenges (from an interface perspective) of "insertObject" for new objects. Hence my semantics note, "a temporary object (including one in Transaction: i'm considering transactions to be a simple wrapper around a temporary object implementation) is not visible to anything that doesn't explicitly reference the python-side instance of it". This is also why it seems to me that any Real objects referenced by or to a temp object need to immediately become temp (part of the transaction). My original interface suggestion is very close to what you just wrote, with cInst.temp() or cClass.temp(...) returning temporary objects, outside of being referenced by any other thread unless explicitly passed by the programmer. Anyways, all just wanking until something gets built. :) I'll get on it. - Luke |
From: Brad B. <br...@bb...> - 2003-04-30 00:39:48
|
On 04/29/03 17:42, Luke Opperman wrote: > > > > I think t.insertObject(c) isn't a good idea. Client(1) is an > > object > > that may be in use in several places, and is presumed to be > > transparently persistent. When you put it into the transaction > > you've > > made temporary for all users of the object. Bad bugs will follow. > > At > > least in threaded situations. > > > > This is why I think the object has to be instantiated as part of > > the > > transaction, or perhaps copied if you don't like instantiation... > > > > t = Transaction() > > c = Client(1) > > ctmp = c.inTransaction(t) > > # or... > > ctmp = Client(1, t) > > > > Ian > > > > I couldn't agree more, this is also refers to the challenges (from an > interface perspective) of "insertObject" for new objects. Hence my > semantics note, "a temporary object (including one in Transaction: > i'm considering transactions to be a simple wrapper around a > temporary object implementation) is not visible to anything that > doesn't explicitly reference the python-side instance of it". This is > also why it seems to me that any Real objects referenced by or to a > temp object need to immediately become temp (part of the > transaction). > > My original interface suggestion is very close to what you just wrote, > with cInst.temp() or cClass.temp(...) returning temporary objects, > outside of being referenced by any other thread unless explicitly > passed by the programmer. > > Anyways, all just wanking until something gets built. :) I'll get on > it. Disclaimer: The answers I'm giving are half-finished, really. I can't say either one is particularly satisfactory, but hopefully someone else will have a few more ideas to add to, and hopefully simplify the mix. Personally, I see many issues to flesh out here yet, and preserve the goal of keeping SQLObject painfully simple to use. Ease-of-use is the reason I switched from Modeling to SQLObject to begin with. The problem is: i. how can SQLObject be transactional? ii. should SQLObject be transactional (or should it be left to using the chosen backend to support it)? There's two main answers that I can see, so far. 1. To be like the Modeling framework, and use the Transaction metaphor, where Modeling uses an EditingContext: http://modeling.sourceforge.net/UserGuide/editing-context.html This adds one more level of indirection between Python objects and database persistence, as the only realistic way for this to be useful and thread-safe is for all data manipulation and retrieval to be done through a Transaction object, which will have a global registry of object ID's for the thread-safety end of things. I already gave an example of what the interface might look like here. SQLObject would still maintain the advantage of being less verbose than Modeling (e.g. new-style properties instead of get/set methods for every column like Modeling, no FetchSpecification like Modeling has, no need to edit a fancy XML file, etc.), but would unavoidably become slightly more complex to learn and use. 2. Scarecrow objects (the "temp" metaphor, except to me "temp" makes it difficult to extrapolate what that's supposed to mean IMHO). So you have: Client(1) to retrieve Client.new(name = "Somebody") to create Client.scarecrow() to create a "brainless" (database-dumb) object The Transaction metaphor could live behind the scenes of a scarecrow, so that scarecrow objects aren't truly persisted, but it's made note of by an object registry of some sort, so: from invoicing import Client ian = Client(1) luke = Client.new(name = "luke") brad = Client.scarecrow(name = "brad") sqlobject_geeks = Client.select('all') Assuming there was only a client with ID 1 in the database to begin with, sqlobject_geeks would now have all three of us in the list. The metaphor for rolling back and committing could be something like: if confirmed_signup: brad.remember() # "commit" the changes to brad else: brad.forget() # "rollback" the changes to brad Of course, this isn't very useful for atomocity. :/ The "temp" or "scarecrow" object (e.g. a single object "transaction") is probably better solved with lazy committing and a save() method needing to be called. Really though, I don't think I see adding a whole new class and metaphor to the framework for this "single object transaction" to be useful. Just my $0.02. -- Brad Bollenbach BBnet.ca |