[Grok-dev] megrok.rdb, Oracle, and views.
Sebastian Ware
sebastian at urbantalk.se
Fri Feb 12 04:06:05 EST 2010
Jeffrey! This is fantastic research you have done. Please post this as
a howto on grok.zope.org! If you don't have time to format it, just
post it as text only.
register and login
http://grok.zope.org/join_form
and go to
http://grok.zope.org/documentation/how-to/
and add howto.
Mvh Sebastian
12 feb 2010 kl. 01.26 skrev Jeffrey D Peterson:
> Hello again,
>
> A while back we looked at some issues I was having with megrok.rdb,
> Oracle
> and reflecting views. I had fiddled around with megrok.rdb until I
> got what
> seemed like something that worked, and it did, but it was a little
> hack-is,
> pulling stuff out of the metadata to not create it. Well after
> several
> emails with the sqlalchemy list, I think I have a better solution,
> this is
> based mostly on advice from Michael Bayer about how views should be
> handled
> in SQLA.
>
> His suggestion was very simple...keep them in a separate metadata
>
> So, to that end, here is what it looks like to me.
>
> Setup stuff (oracled.py):
>
> DSN = 'oracle://webserv@MIGR75X'
> engine_factory = EngineFactory(DSN, echo=True)
> grok.global_utility(engine_factory, direct=True)
>
> scoped_session = GloballyScopedSession()
> grok.global_utility(scoped_session, direct=True)
>
> # Keep two metadata and fire up engines for both
> reflected_views_md = rdb.MetaData()
> created_md = rdb.MetaData()
>
> @grok.subscribe(IEngineCreatedEvent)
> def reflected_engine_created(event):
> rdb.setupDatabase(reflected_views_md, True)
>
> @grok.subscribe(IEngineCreatedEvent)
> def engine_created(event):
> rdb.setupDatabase(created_md)
>
>
> Changes in megrok.rdb:
>
> In setup.py I simply added a parameter and conditional to the
> setupDatabase
> function:
>
> def setupDatabase(metadata, skip_create=False):
> """Set up of ORM for engine in current site.
>
> This will:
>
> * reflect any reflected tables that need to be reflected from the
> database
> into classes.
>
> * create any tables in the database that haven't been yet
> reflected.
> """
> reflectTables(metadata)
> if not skip_create:
> createTables(metadata)
> notify(DatabaseSetupEvent(metadata))
>
>
> Then when reflecting views simply use the correct metadata and set
> the flag
> skip_create to True. The reason there was always trouble was that
> rdb.setupDatabase _always_ called create_all() regardless. SQLA,
> while it
> can see that reflected tables exist in the DB it can't do the same
> with
> views and would try and create those views as tables if create_all()
> was
> called with the metadata containing the reflected views.
>
> This is a very small subtle change that would not at all effect
> existing
> code.
>
> And then you can fire up reflected views to your heart's content:
>
>
> from portal.lib.db.oracled import reflected_views_md as metadata1,
> created_md as metadata2
>
> class TestSA(rdb.Container):
> pass
>
> class CrarySalesPart(rdb.Model):
> """
> Reflected view, notice the metadata that uses the
> rdb.setupDatabase with
> skip_create=True,
> Don't run create_all() on this metadata SQLA will see this as a
> table
> that needs creation and
> Try and create it in the DB, which we do not want.
> """
> rdb.metadata(metadata1)
> rdb.reflected()
> rdb.tablename('crary_sales_part')
> rdb.tableargs(schema='crar1app', useexisting=True)
>
> contract = Column('contract', String, nullable=False,
> primary_key=True)
> catalog_no = Column('catalog_no', String, nullable=False,
> primary_key=True)
>
> class CraryOutputTab(rdb.Model):
> """
> Reflected table, notice the metadata that uses the
> rdb.setupDatabase
> with skip_create=False(default),
> SQLA handles the create properly because it can see this as a
> table and
> therefore will not try and create it.
> This metadata would then also be used for any tables you did want
> to be
> dynamically created as well.
> """
> rdb.metadata(metadata2)
> rdb.reflected()
> rdb.tablename('crary_output_tab')
> rdb.tableargs(schema='crar1app', useexisting=True)
>
>
> I don't know about you but this method feels right to me, and it
> also causes
> a lot less pain.
> Very little code to change and a lot of functionality gained.
>
> Here is a diff of setup.py:
>
> 10c10
> < def setupDatabase(metadata):
> ---
>> def setupDatabase(metadata, skip_create=False):
> 21c21,22
> < createTables(metadata)
> ---
>> if not skip_create:
>> createTables(metadata)
>
>
> Regards,
>
> Jeff Peterson
>
> _______________________________________________
> Grok-dev mailing list
> Grok-dev at zope.org
> https://mail.zope.org/mailman/listinfo/grok-dev
More information about the Grok-dev
mailing list