2011-11-06 8 views
13

estoy teniendo un problema donde consigo un error como este:SQLAlchemy StaleDataError en la eliminación de elementos insertados a través de ORM sqlalchemy.orm.exc.StaleDataError

"MyPyramidApplication Error"<class 'sqlalchemy.orm.exc.StaleDataError'>: DELETE statement on table 'page_view' expected to delete 6 row(s); Only 0 were matched. 

lo tanto, tengo una buena idea de lo está causando el problema, pero no he podido resolverlo.

Tengo un modelo page_view, que tiene una clave externa en page_id y user_id.

Esto es lo que se ve el modelo como:

page_view_table = sa.Table(
    'page_view', 
    metadata, 
    sa.Column('id', sa.Integer, primary_key=True), 
    sa.Column('page_id', sa.Integer, sa.ForeignKey('guide.id')), 
    sa.Column('user_id', sa.Integer, sa.ForeignKey('user.id')), 
    sa.Column('last_view', sa.DateTime, nullable=False), 
    sa.UniqueConstraint('user_id', 'page_id'), 
    mysql_engine='InnoDB', 
    mysql_charset='utf8mb4' 
) 

Esto es lo que las relaciones se ven como

orm.mapper(Page, page_table, 
    properties = { 
     'users_viewed': sa.orm.relation(
      User, 
      secondary=page_view_table, 
      backref='page'), 
    } 
) 

estoy añadiendo algunos artículos a mi base de datos utilizando una instrucción de inserción, algo similar a esto:

ins = model.page_view_table.insert() 
sql = str(ins) 
sql += ' ON DUPLICATE KEY UPDATE last_view = :last_view' 
session = model.Session() 
session.execute(sql, page_views) 
mark_changed(session) 

Por lo que puedo ver en los registros, las transacciones se comprometen correctamente y veo los artículos en la base de datos.

Sin embargo, cuando intento eliminar el elemento de la página utilizando el ORM, aparece la excepción StaleDataError. Al mirar los registros, veo que el ORM emite una instrucción de eliminación pero luego retrocede debido al error.

He intentado experimentar con session.expire_all() así como session.expunge_all() justo después de la instrucción de inserción, pero no fueron muy útiles y sigo teniendo el error.

Esto es lo que veo en los registros de SQLAlchemy.

2011-11-05 18:06:08,031 INFO [sqlalchemy.engine.base.Engine][worker 3] DELETE FROM page_view WHERE page_view.page_id = %s AND page_view.user_id = %s 
2011-11-05 18:06:08,031 INFO [sqlalchemy.engine.base.Engine][worker 3] (13818L, 259L) 
2011-11-05 18:06:08,032 INFO [sqlalchemy.engine.base.Engine][worker 3] DELETE FROM page_view WHERE page_view.page_id = %s AND page_view.user_id = %s 
2011-11-05 18:06:08,033 INFO [sqlalchemy.engine.base.Engine][worker 3] (13818L, 259L) 
2011-11-05 18:06:08,033 INFO [sqlalchemy.engine.base.Engine][worker 3] ROLLBACK 

pensé que la declaración de eliminación doble era un sospechoso, tal vez apuntando a una relación ORM mal configurado, pero no creo que ese es el caso.

Respuesta

3

Supongo que puedo dar una sugerencia sobre este problema. La versión corta es: "Probablemente tendrá que modificar datos en la Base de datos manualmente para resolver el problema".

La versión más larga: tuve un problema similar con SQLite. He mapeado la siguiente tabla:

ingredients = Table('ingredients', metadata, 
    Column('recipe_title', Unicode, ForeignKey('recipes.title'), primary_key=True), 
    Column('product_title', Unicode, ForeignKey('products.title'), primary_key=True), 
    Column('amount', Integer, nullable=False), 
    Column('unit_title', Unicode, ForeignKey('units.title'))) 

¿Ve esa clave primaria compuesta? De alguna manera logré insertar dos filas con el mismo par recipe_title/product_title. Me sorprendió descubrir que no había una sola restricción en el lado de SQLite para esta tabla (sin clave principal, sin clave de anuncio, era simplemente una tabla simple), pero bueno, esa es la forma en que funciona sqlalchemy, no mi negocio.

Luego, cuando traté de eliminar un objeto persistente que involucra esas dos filas, sqlalchemy vio que se violaron sus restricciones y arrojó el 'StaleDataError'. Finalmente, tuve que eliminar una fila duplicada manualmente de la tabla SQLite.

1

Aunque las columnas se pueden marcar como primary_key, asegúrese de que esto también se aplique en el nivel de la base de datos (por ejemplo, cuando la base de datos fue creada por alguna herramienta diferente). En MySQL esto significa asegurarse de que sean PRIMARY KEY y no solo KEY.

En mi caso, había 2 columnas marcadas como primary_key (compuestas) pero había varias filas que contenían las mismas (supuestamente) únicas id 's.

+0

Para mejorar esta respuesta, modifique la redacción --- como "Aunque las columnas se pueden marcar como primary_key, la base de datos puede no aplicarlas como tales. Asegúrese de que sean PRIMARY KEY y no KEY haciendo " O if esta no es una respuesta a la pregunta original, por favor bórrelo. –

Cuestiones relacionadas