On Jun 1, 2007, at 10:27 PM, Mike Orr wrote:

> Multiple engines make my head spin.  Why do you need that unless
> you're connecting to two different databases in the same application?

thats what it would be needed for, yes.

> And even if you did, wouldn't you define a second top-level
> session_context to bind it to, with its own different metadata and
> tables, and never the twain shall mix?

two separate sessions ?  you might have a set of objects which are  
saved to more than one database, but are dealt with in one  
transaction.  the SessionTransaction actually performs a poor-mans  
two-phase commit in this case, where it executes the flush()  
statements for each database before calling commit() on all of them.   
a ticket in trac exists which contains part of a patch that will wire  
in actual two-phase commit hooks for databases which support it  
directly (like postgres).

while you might have the tables from the distinct databases  
associated with different MetaData objects,  that doesnt change the  
fact that the session needs to know about the engines associated with  
each MetaData.   but then again, the engine->MetaData binding idea is  
not really needed at all, except for the convenience of self- 
executing statement objects without needing to pass around an engine  
or a connection.

> I don't want a registry of
> engines or something in the 'g' object.  What I want is a simple
> out-of-the box configuration for simple sites, but more robust than
> what Pylons currently has.  Maybe we'll have to come up with separate
> simple and advanced configurations if others need multiple engines and
> whatnot.

i think an object tailored to Pylons should be created here which  
encapsulates those concepts.

>
> I also don't like how pylons.database initializes a session_context at
> import time rather than providing a create_session_context function,
> so that's another thing to add to my patch.  Otherwise if you can't
> use pylons.database.create_engine() for some reason, you have to
> duplicate a lot of code to recreate or bypass the default
> session_context, and this includes writing stub functions because
> SessionContext takes a session factory function with takes a
> create_engine function, so there's no way to customize the
> create_engine from the SessionContext constructor directly.

yeah actually i think id just skip pylons.database altogether if i  
were writing a new app, and just make my own engine / session  
context.  we're talking three lines of code here.

>
> Methinks SQLAlchemy is contributing to the problem with its long
> hierarchy of engine -> metadata -> session -> session_context, but I
> don't have the expertise to say what might be better.  But certainly
> it's annoying that:
>
> - SessionContext doesn't take both create_engine and make_session
> arguments, or arguments to pass through to those, and build your ideal
> engine -> session -> session_context hierarchy on the fly.  Instead
> you have to create a dummy make_session function just to tell it which
> create_engine to use.  This is part of why overriding Pylons' default
> session_context requires reimplementing three whole functions.

OK well i dont even like that SessionContext requires a session  
creation function at all, since for many cases its just the default  
create_session function.  this whole deal with the session binding to  
the engine wasnt widely used before pylons.  i would think the most  
obvious arguments wouldnt be create_engine, but just "engine",  
wouldnt it ?

>
> - This is a part of the previous, but SessionContext in the manual
> says, "A common customization is a Session which needs to explicitly
> bind to a particular Engine."  Yes, so why doesn't SQLAlchemy provide
> a way to handle this common case without the user having to define his
> own make_session?  Again, SessionContext -- or a
> create_session_context function -- could do this for you if you pass
> an 'engine' argument.

oh ok, there we go.  i dont have a problem with that.  Dan  
(SessionContext's creator) hasnt been chiming in lately so i guess we  
can change his API a little bit :)  Also the notion that  
SessionContext should be combined with Session is somethign to look  
at, although they are separate at the moment so that users can first  
get familiar with Session, and then when they realize they need to  
keep one of them around within threads they can then get their head  
around SessionContext.  by combining it all together people would  
just be more overwhelmed and follow various flawed recipes more  
blindly than they do now :).


>
> - Metadata seems like an implementation detail.  I have to define a
> metadata just to pass it to my Table's, then I never use it again.

its used for locating other tables when a ForeignKey is detected, as  
well as sorting them all for a create_all/drop_all.   so a context of  
some kind is needed.


> There is global_connect() which hides it, but its use seems
> discouraged.  Plus global_connect gets into all that DynamicMetaData
> complication, such as whether it will autoconnect properly in the
> other threads.  Perhaps what I'm asking for is a global_bound_connect
> or something?

yes the whole global thing was something i never liked.  I dont like  
application wide configurations that are bound at the module level.   
people are likely to get confused pretty quick when they start  
putting multiple applications, or sub-applications, within the same  
python interpreter and start getting name collisions and such.  by  
exposing MetaData and Engine, the developer has to define the scope  
of these things by his or herself, and thats how it should be.  I  
cringe when i see people using global_connect().

DynamicMetaData was then inspired exactly by this:

http://www.sqlobject.org/class-sqlobject.dbconnection.ConnectionHub.html

and it wasnt my idea at all, it was TG folks looking to adapt  
ConnectionHub to sqlalchemy.  it originally began as a ProxyEngine,  
back when Tables were bound straight to the Engine.  But these days,  
SA is a lot more high level than that, we have Session with its own  
engine, etc. so DMD is not so relevant now (unless youre doing lots  
of constructed SQL with thread-local engines).


>   I can see why the metadata can't be subsumed into the
> engine because you may want to connect the same metadata back and
> forth if you're copying data from one database to another.  And I can
> see why it can't be subsumed into create_session_context because you
> need it before that to autoload the tables.  So it's kind of the
> centerpiece that holds those two together and also holds the tables.
> So maybe making the metadata less obtrusive is insolvable.

maybe a better interface would have been this:

meta = MetaData()

users = meta.create_table("users", Column("user_id")...)

that would have circumvented the emotional impact of metadata being  
an argument rather than the factory.  I was going for a particular  
look when i came up with Table/Column, i..e that it would look like  
regular SQL DDL.

>
> I don't know whether the answer is to collapse the hierarchy so it's
> not function-calling-function-calling-function or what.  Probably that
> would be too disruptive to existing users and make SQLAlchemy less
> flexible/useful.  But I just wonder how much of this hierarchy is
> really necessary/useful, and how much should just be subsumed in an
> uber one-session-context-to-rule-them-all like pylons.database does.

well Pylons has raised the bar a little by going for the  
session.bind_to=theengine idea, which was decidedly less common than  
the usual BoundMetaData idea.   it is more flexible particularly for  
an application that shares the same set of Table objects among  
multiple databases, which is what Ben was very much going for, i.e.  
an application that supports multiple hosted accounts, each account  
having its own private database schema.  I dont know if he remembers  
but he was IM'ing me about that all day long many months ago :).

>
> I'm only doing ctx.current.bind_to because Pylons makes that easy, and
> because as a naive user I wouldn't know whether it's safe to stray
> away from that recommendation.  Users know not to share a session
> between threads, that they should use session_context even though they
> don't quite understand what it does, but they can get confused whether
> an engine or metadata or anything else that's accessed through a
> session_context is compatible with one declared or used at top level
> in another thread.
>
> I would be in favor of a more straightforward approach in my model:
>
> engine = create_engine(...)
> meta = BoundMetaData(engine)
> ctx = create_session_context(engine, meta, session_options)
>

like I said we can make a nicer SessionContext constructor.   but  
above, im not sure how much sense it makes to have BoundMetaData  
combined with the engine attached to the session directly.  the most  
major issue im seeing in this area is that people are binding the  
engine twice like that and its for no reason, it creates  
confusion.    if you have BoundMetaData, youre done with the engine.   
sessioncontext/session doesnt need it, it will use it from the tables  
directly.

I think what we have to look at re: pylons is its insistence on even  
using the session(bind_to=engine) model in the first place.  if it  
just used BoundMetaData, you can just create sessions freely without  
binding them to anything.  the notion of "multple engines sharing the  
same Table objects" is just one particular execution model which i  
think is not at all the norm.



--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to