On Nov 9, 2010, at 3:44 AM, Torsten Engelbrecht wrote:

> Hi,
> 
> I need to use dynamic table names in a project (though for the same
> object). Now I got the following problem:
> - I fetch data from an RSS feed to fill my database. Its an RSS feed
> with many pages, each page has around 100 items
> - I fetch the first page and create a table + mapper for a dynamic id
> (called "my_id" below)
> - then I do session.add and session.commit for each item in the feed,
> everything ok so far
> - after I fetch the second page ("my_id" is the same), I attempt to
> recreate table and mapper (see code below) or simply readd them if
> they already exist, that seems working as well
> - I do the same for each item in the feed as the first time, but this
> time it raise the following exception:
> "sqlalchemy.orm.exc.FlushError: Instance <MyModel at 0x1bc1590> has a
> NULL identity key.  Check if this flush is occuring at an
> inappropriate time, such as during a load operation."
> 
> Here my data model (simplified) and the code to simply save a new item
> from the feed:
> 
> ===
> import sqlalchemy
> from sqlalchemy import import orm
> 
> mymetadata = sqlalchemy.MetaData()
> 
> class MyModel(object):
>    def __init__(self, **kwargs):
>        title = kwargs.get('title')
>        body = kwargs.get('body')
> 
> class MyModelTable(object):
>    def __init__(self, my_id):
>        metadata = mymetadata
>        table_name = 'mymodel_%s' % my_id
>        self.table = sqlalchemy.Table(table_name, metadata,
>            sqlalchemy.Column('id', sqlalchemy.Integer,
> primary_key=True),
>            sqlalchemy.Column('title', sqlalchemy.String(255),
> index=True),
>            sqlalchemy.Column('body', sqlalchemy.Text),
>        useexisiting=True)
>        self.table.create(get_engine(), checkfirst=True) #get_engine()
> is helper function to retrieve the engine (not listed here)
>        orm.mapper(MyModel, self.table)
> 
> def save_items(my_id, items): #assuming items is already parsed and
> saved in a list
>    model_table = MyModelTable(my_id)
>    session = orm.sessionmaker(bind=get_engine(), autocommit=False,
>                                    autoflush=True)
>    for item in items:
>        item_data = dict(title=item['title'],
> body=item['description'])
>        new_model_instance = MyModel(**item_data)
>        session.add(new_model_instance)
>    session.commit()
>    session.close()
>    orm.clear_mappers() #to avoid the exception when mapping the same
> object to anoher ot the same table
> ===
> 
> 
> save_items() is called each time a new page is fetched (either for the
> same "my_id") or another one.
> This FlushError only happens when I have more than one page for the
> same "my_id" and they are saved one after another. I also never
> happens for the first page, neither for different "my_id"'s when
> staying with one page.
> According to the release notes of SQLAlchemy 0.6.5 this exception
> raises when
> ===
> "Added an assertion during flush which ensures
> that no NULL-holding identity keys were generated
> on "newly persistent" objects.
> This can occur when user defined code inadvertently
> triggers flushes on not-fully-loaded objects. "
> ===
> Though I don't see  why it happens in my example.  I appreaciate any
> help.  Thanks

While the above code uses some patterns that are unnecessary, there's nothing 
about it which would cause that error to occur.   To my knowledge, the only way 
that particular condition arises is if a flush occurs at an inappropriate time, 
namely within an object load, which does not seem to be the case based on your 
stack trace.    So I am extremely curious how you're getting that to occur.

The advised way to do "entity name", which is roughly the pattern you have 
above, that is, one which maps the same class to multiple tables, is to create 
new classes for each table.   These can be ad-hoc subclasses of MyModel if the 
base class has other significant behaviors.   A description of this is at 
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/EntityName .    You'd probably 
want to pull your mapped classes from a dictionary, and if not present *then* 
create the Table object and mapper - the regeneration of the Table above with 
useexisting is not an optimal way to do things.





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

Reply via email to