[sqlalchemy] Re: Single table inheritance and mapping against a selectable

2007-07-28 Thread Gaetan de Menten

On 7/28/07, Michael Bayer [EMAIL PROTECTED] wrote:

 those are fine with me.  if someone could add a ticket and/or
 implement that would be helpful.

http://www.sqlalchemy.org/trac/ticket/696

-- 
Gaƫtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: permanent objects and sessions

2007-07-28 Thread Michael Bayer

your best option is probably to keep the objects in a session that's
specifically for the global objects.  Most important is that if you
are using multiple threads, you never call flush() on this session.
With regards to threadsafety in this case, as long as the session is
not used for a flush() operation, you should be OK.  The connection
used for querying for a non-transactional session is checked out
distinctly per-operation, so there will be no conflicts there.  The
second place of concern is when the Query retrieves existing objects
from the identity map as it loads rows, and as it places newly loaded
objects into the identity map;  multiple threads might both create the
same object and might both store it in the identity map; only one
would actually remain in the map.  However for a purely read-only
situation, your application will still see the same kinds of objects,
and even the object that was replaced, which still would remain
established in a parent collection, can still call upon that session
to issue further lazyloads.

I might look into adding a flag in 0.4 session readonly, which
produces a session that disallows flush() and places a single mutex
around query.instances(); then youd have a completely threadsafe read-
only session.  its only a couple of lines.







On Jul 28, 10:09 am, MuTPu4 [EMAIL PROTECTED] wrote:
 One of my tables represents a tree structure which I want to be cached
 in memory during my application's lifetime. Problem is that i can not
 figure out how to organize sessions acquisition/releasing. I am
 loading the whole hierarchy using one session and then closing it
 which makes objects detached. Then duaring modifications and lazy
 loads across relations I am getting an errors like:
 InvalidRequestError: Parent instance class
 'si.core.category.Category' is not bound to a Session, and no
 contextual session is established; lazy load operation of attribute
 'parent' cannot proceed
 Creating a new session and reattaching existing objects to it using
 update( ) helps but I hope that reattaching the whole hierarchy is not
 the right way. Is there a way to keep permanent objects in memory
 without holding initial session for the whole application lifetime?

 Sorry for my bad English.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: permanent objects and sessions

2007-07-28 Thread michael

On Sat, 28 Jul 2007 14:36:45 -
Michael Bayer [EMAIL PROTECTED] wrote:

 
 your best option is probably to keep the objects in a session that's
 specifically for the global objects.  Most important is that if you
 are using multiple threads, you never call flush() on this session.
 With regards to threadsafety in this case, as long as the session is
 not used for a flush() operation, you should be OK.  The connection
 used for querying for a non-transactional session is checked out
 distinctly per-operation, so there will be no conflicts there.  The
 second place of concern is when the Query retrieves existing objects
 from the identity map as it loads rows, and as it places newly loaded
 objects into the identity map;  multiple threads might both create the
 same object and might both store it in the identity map; only one
 would actually remain in the map.  However for a purely read-only
 situation, your application will still see the same kinds of objects,
 and even the object that was replaced, which still would remain
 established in a parent collection, can still call upon that session
 to issue further lazyloads.
 
 I might look into adding a flag in 0.4 session readonly, which
 produces a session that disallows flush() and places a single mutex
 around query.instances(); then youd have a completely threadsafe read-
 only session.  its only a couple of lines.

Sorry if this is naive.. but.. if the data is 'readonly' and can not
be flushed, why keep the very valuable thread, session, and db
connection open?  Why not just load data into a global variable and be
done with it?


-- 

michael



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: permanent objects and sessions

2007-07-28 Thread MuTPu4

On Jul 28, 5:36 pm, Michael Bayer [EMAIL PROTECTED] wrote:
 your best option is probably to keep the objects in a session that's
 specifically for the global objects.  Most important is that if you
 are using multiple threads, you never call flush() on this session.
 With regards to threadsafety in this case, as long as the session is
 not used for a flush() operation, you should be OK.  The connection
 used for querying for a non-transactional session is checked out
 distinctly per-operation, so there will be no conflicts there.  The
 second place of concern is when the Query retrieves existing objects
 from the identity map as it loads rows, and as it places newly loaded
 objects into the identity map;  multiple threads might both create the
 same object and might both store it in the identity map; only one
 would actually remain in the map.  However for a purely read-only
 situation, your application will still see the same kinds of objects,
 and even the object that was replaced, which still would remain
 established in a parent collection, can still call upon that session
 to issue further lazyloads.

 I might look into adding a flag in 0.4 session readonly, which
 produces a session that disallows flush() and places a single mutex
 around query.instances(); then youd have a completely threadsafe read-
 only session.  its only a couple of lines.
Thanks for your replay.
Probably my case is somewhat more compilcated but I thought that it is
rather common. It may be outlined as follows.
I have a long-running application (web server) which resopnds to
frequent queries users (pages fetch). The data is organized into
hierarchical directory which is represented by Nodes and Items:
[code]
self.categories_table = Table(
'categories'
  , self.metadata
  , Column( 'category_id', Integer, primary_key = True )
  , Column( 'name', String, nullable = False, index = True )
  , Column( 'parent_category_id', Integer, nullable = True, index
= True )

  , ForeignKeyConstraint( [ 'parent_category_id' ],
[ 'categories.category_id' ], onupdate = 'CASCADE', ondelete =
'CASCADE' )
)
self.items_table = Table(
'items'
  , self.metadata
  , Column( 'item_id', Integer, primary_key = True )
  , Column( 'name', String, nullable = False, index = True )
  , Column( 'parent_category_id', Integer, nullable = False, index
= True )

  , ForeignKeyConstraint( [ 'parent_category_id' ],
[ 'categories.category_id' ], onupdate = 'CASCADE', ondelete =
'CASCADE' )
)
[/code]
I want to have a global preloaded tree structure for fast access
(frequent reads and infrequent modifications) with application's
lifetime and ability to fetch Items as needed. I wanted to use some
nice automation features of SA's ORM (lazy
loads across relations, automatic DB updates etc) so I have come up
with the following solution:
[code]
class Category( object ) :
  def __init__( self, name, parent_category ) :
self.name = name
self.parent = parent_category

class Item( object ) :
  def __init__( self, name, parent_category ) :
self.name = name
self.parent = parent_category
[/code]
[code]
  #data mapping
  self.items_mapper = mapper( item.Item, self.items_table, properties
= {
'parent' : relation( Category, uselist = False, lazy = False )
  } )
  self.categories_mapper = mapper( category.Category,
self.categories_table, properties = {
'children' : relation( Category, backref = backref( 'parent',
remote_side = [ self.categories_table.c.category_id ] ), cascade =
'all' )
  } )
[/code]
[code]
  #application init
  session = self.db.create_session( )
  self.root =
session.query( Category ).selectone( Category.c.parent_category_id ==
None )
  session.close( )
[/code]
[code]
  #hypothetical code in one of the threads
  session = self.db.create_session( )
  new_obj = Category( 'test', directory.root )
  session.save( new_obj )
  session.flush( )
  print new_obj.parent.name
  len( new_obj.children )
  subitems = session.query( Item ).select_by( parent_category_id =
directory.root.category_id )
  session.close( )
[/code]
Now I see that this approach is not viable as-is. Maybe there is a way
to adopt it using modules like SessionContext and assignmapper?
If there is no such a way, I currently see two solutions:
1. Just dont use permanent objects and fetch an appropriate portions
of informations at every request relaying on DB's cache and loopback
network optimizations.
2. Using basic SA features implement an ad-hoc ORM as a part of
Category and Item classes which will use given session to fetch/insert/
uopdate data.
Maybe someone can point me to another not so painful solution?


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit 

[sqlalchemy] Newbie question about transactions

2007-07-28 Thread mc

In the following code, I intended that nothing will be inserted into
the table because the transaction fails and is rolled back. What
actually happens is that the first insert is not rolled back because
it s committed by itself.
What is the correct way to achieve my goal?
TIA

from sqlalchemy import *
db=create_engine('mysql://user:pw@localhost/db')
cn= db.connect()
cn.execute(DROP TABLE IF EXISTS test)
cn.execute(CREATE TABLE test (`id` bigint(20) NOT NULL , PRIMARY KEY
(`id`))
 
ENGINE=InnoDB)
db.echo=True

md=BoundMetaData(db)
t=Table('test', md, autoload = True)

trans = cn.begin()
try:
insert(t).execute(id=332)
insert(t).execute(id=332)
trans.commit()
except:
trans.rollback()
raise


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Newbie question about transactions

2007-07-28 Thread mc

Thanks.
Can you point me to the place in the doc where this is discussed?
I was under the impression that I had one connection only in this
scenario.

TIA


On Jul 28, 11:09 pm, Michael Bayer [EMAIL PROTECTED] wrote:
 On Jul 28, 2007, at 2:54 PM, mc wrote:



  md=BoundMetaData(db)
  t=Table('test', md, autoload = True)

  trans = cn.begin()
  try:
  insert(t).execute(id=332)
  insert(t).execute(id=332)
  trans.commit()
  except:
  trans.rollback()
  raise

 the statements must be executed relative to the connection which
 contains the transaction:

 cn.execute(insert(t), id=332)


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Newbie question about transactions

2007-07-28 Thread Michael Bayer

discussion starts here:

http://www.sqlalchemy.org/docs/dbengine.html#dbengine_connections

covers some options available to you including using a thread local  
connection.


On Jul 28, 2007, at 5:07 PM, mc wrote:


 Thanks.
 Can you point me to the place in the doc where this is discussed?
 I was under the impression that I had one connection only in this
 scenario.

 TIA


 On Jul 28, 11:09 pm, Michael Bayer [EMAIL PROTECTED] wrote:
 On Jul 28, 2007, at 2:54 PM, mc wrote:



 md=BoundMetaData(db)
 t=Table('test', md, autoload = True)

 trans = cn.begin()
 try:
 insert(t).execute(id=332)
 insert(t).execute(id=332)
 trans.commit()
 except:
 trans.rollback()
 raise

 the statements must be executed relative to the connection which
 contains the transaction:

 cn.execute(insert(t), id=332)


 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: permanent objects and sessions

2007-07-28 Thread MuTPu4

On Jul 28, 11:08 pm, Michael Bayer [EMAIL PROTECTED] wrote:
 theres nothing at all wrong with the above; the only adjustments Id  
 make are to a. leave a global session open for your directory.root,  
 and b. remove all cascade rules from the parent relation (in this  
 case using backref=backref('parent', cascade=None), so that when you  
 attach the out-of-session Category as a 'parent' to your new  
 Category, the child category can get a parent_id value but the parent  
 Category object is otherwise unaffected.
I have tried to use global session object for all DB operations
without synchronization and it seems to work perfectly on simple
tests. It remains only to add application-level synchronization. But I
don't quite understand your second advise about cascading. I thought
that in case of using global session object none of Category instances
can be detached. Am I missing something?


 If that produces problems, the more official way to go about it is  
 to merge() the parent Category into your current session:

 parent = session.merge(directory.root)

 new_obj = Category('test', parent)
 ...

 the merge() operation will create a copy of parent within the local  
 session.  It will usually issue a fetch operation from the database  
 in order to get the most recent data for the particular Category.
The problem with this solution is that I dont always know the part of
the hierarchy that I want to be in the current session. I am relying
on implicit lazy loads and the client-code may want to access a large
parts of the tree using new session, reattaching all of these nodes
which makes my cache strategy useless.

 this is what SA is currently more tailored towards; being able to  
 load data fresh from the DB with as few queries as possible, thereby  
 avoiding the data freshness issues that come when second-level  
 caches are introduced.  What youre really trying to do here is dual-
 purpose the Session as a second level cache, which is possible as I  
 outlined using merge(), but its not completely ideal.   SA will  
 eventually implement a real second level caching system; it will  
 involve producing new object instances on the fly which are bound to  
 a particular session; just the actual data from those objects would  
 be cached instead of being fetched from the DB (and it also will use  
 synchronization similar to that outlined above).
From the point of view of my example it would be usefull to decouple
loading/storing API from mapped objects themselfs. If it is possible
it will be usefull opportunity imho.

Thank you kindly for your help and advices.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: permanent objects and sessions

2007-07-28 Thread Michael Bayer


On Jul 28, 2007, at 8:46 PM, MuTPu4 wrote:


 On Jul 28, 11:08 pm, Michael Bayer [EMAIL PROTECTED] wrote:
 theres nothing at all wrong with the above; the only adjustments Id
 make are to a. leave a global session open for your directory.root,
 and b. remove all cascade rules from the parent relation (in this
 case using backref=backref('parent', cascade=None), so that when you
 attach the out-of-session Category as a 'parent' to your new
 Category, the child category can get a parent_id value but the parent
 Category object is otherwise unaffected.
 I have tried to use global session object for all DB operations
 without synchronization and it seems to work perfectly on simple
 tests. It remains only to add application-level synchronization. But I
 don't quite understand your second advise about cascading. I thought
 that in case of using global session object none of Category instances
 can be detached. Am I missing something?

when you say:

c = Category('foo', root)

and you then attach 'root' using c.parent = root, a cascade rule  
associated with the 'parent' relation will attempt to add the newly  
attached 'root' Category to the local session.  Since 'root' is  
already in a different Session, this will raise an error.  so  
instead, make a local copy of root using merge() before using it in  
a local session.

or if not, you can even just associate using the column based  
attributes before flushing:

c = Category('foo')
c.parent_id = root.id

above, you arent attaching any of your cached objects to your new  
Category, just setting the appropriate column-valued elements on  
it.   This way you limit the manipulations to just your new object  
without modifying your cache's structure or state at all.


 the merge() operation will create a copy of parent within the local
 session.  It will usually issue a fetch operation from the database
 in order to get the most recent data for the particular Category.
 The problem with this solution is that I dont always know the part of
 the hierarchy that I want to be in the current session. I am relying
 on implicit lazy loads and the client-code may want to access a large
 parts of the tree using new session, reattaching all of these nodes
 which makes my cache strategy useless.

merge() will cascade by default.  when you merge() root, it also merge 
()s everything currently attached to root (this is also  
configurable).  its actually not that efficient of an operation if  
your structure is very large.  you probably dont need to load very  
much into your local session though, just whatever gets immediately  
associated with whatever objects you're flushing.

 From the point of view of my example it would be usefull to decouple
 loading/storing API from mapped objects themselfs. If it is possible
 it will be usefull opportunity imho.

you can work with the objects detached from any session, but when you  
want to put them into a local Session and save them you need to  
either put them there, or make copies of them.  the whole way unit-of- 
work tools like SQLAlchemy's ORM function is by keeping track of  
object state and identity; if we allowed you to put your Category  
object in your cache session A, as well as session B used in a  
particular request that wants to save data, and session C used in yet  
another concurrent request that wants to save data, it should be  
apparent that manipulating the object in all those concurrent threads  
is going to produce inconsistent and conflicting state between each  
thread...and manipulation operations are extremely common; for  
example, when you attach root to the new Category c via its  
parent attribute, the backref is also appending c to root's  
children attribute automatically.  theres not really any reasonable  
option to having local, non-thread-shared copies of the objects which  
you're manipulating.

Also, you've stated that you want lazyloads to occur, so already, you  
do want load operations embedded into mapped objects.  if you didnt  
want that, you could leave your cached objects out of any session  
entirely.

the only thing to follow here is, for all your read-only operations,  
just use your cache.  for any kind of im going to save something  
operation, just load what you need fresh from the database into a  
local session, put it all together, and flush.   by going through the  
effort to tailor your application this way you help to guarantee the  
consistency of your objects and the data that goes into your database.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] querying many-to-many (WordPress)

2007-07-28 Thread Max Ischenko

Hello,

I'm using SQLAlchemy to access my WordPress database and I need to
query posts from particular category.

There is a many-to-many mapping between wp_posts and wp_categories
table, throught wp_post2cat table.

I was able to come up with the following code:

cats = self.meta.tables['wp_categories']
posts = self.meta.tables['wp_posts']
post2cat = self.meta.tables['wp_post2cat']
q = self.session.query(WordpressPost)
q = q.filter(WordpressPost.c.status=='publish')
q = q.filter(WordpressCategory.c.slug=='sitenews')
q = q.filter(post2cat.c.post_id==posts.c.ID)
q = q.filter(post2cat.c.category_id==cats.c.cat_ID)

It works correctly but seems too verbose to me. Basically I do two
joins by hand. I suspect SQLAlchemy can do this for me, just can't
figure out how. Help, please?

Max.

P.S.: I have:

mapper(WordpressCategory, wp_categories_tbl , properties={
'id' : wp_categories_tbl.c.cat_ID,
...
})
mapper(WordpressPost, wp_posts_tbl, properties={
'id' : wp_posts_tbl.c.ID,
   ...
'categories': relation(WordpressCategory,
secondary=wp_post2cat_tbl),
})


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---