SQLAlchemy StaleDataError при удалении элементов, вставленных с помощью ORM sqlalchemy.orm.exc.StaleDataError - PullRequest
14 голосов
/ 06 ноября 2011

У меня возникла проблема, при которой я получаю сообщение об ошибке, подобное этому:

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

Итак, у меня есть хорошая идея, что является причиной проблемы, но я не смог ее решить.

У меня есть модель page_view, которая имеет внешний ключ на page_id и user_id.

Вот как выглядит модель:

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'
)

Воткак выглядят отношения

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

Я добавляю некоторые элементы в свою базу данных с помощью оператора вставки, что-то похожее на это:

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)

Насколько я могу судить из журналовтранзакции фиксируются правильно, и я вижу элементы в БД.

Однако, когда я пытаюсь удалить элемент страницы с помощью ORM, я получаю исключение StaleDataError.Просматривая журналы, я вижу, что ORM выдает оператор удаления, но затем откатывается из-за ошибки.

Я попытался поэкспериментировать с session.expire_all(), а также session.expunge_all() сразу после оператора вставки, но они не былиЭто не очень полезно, и я все еще вижу ошибку.

Вот что я вижу в журналах 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

Я думал, что оператор двойного удаления был подозрительным, возможно, указывает на неправильно настроенный ORMотношения, но я не думаю, что это так.

Ответы [ 2 ]

7 голосов
/ 02 апреля 2012

Полагаю, я могу дать подсказку по этой проблеме. Краткая версия: «Вам, вероятно, придется изменить данные в базе данных вручную, чтобы решить проблему».

Более длинная версия: у меня была похожая проблема с SQLite. У меня была следующая таблица:

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')))

видите этот составной первичный ключ? Мне как-то удалось вставить две строки с одной и той же парой recipe_title / product_title. Я был удивлен, обнаружив, что на стороне SQLite не было ни одного ограничения для этой таблицы (без первичного ключа, без ключа-ключа - это была просто обычная таблица), но хорошо - вот так идет sqlalchemy, а не мой бизнес.

Затем, когда я попытался удалить постоянный объект, включающий эти две строки, sqlalchemy увидел, что его ограничения были нарушены, и выдал «StaleDataError». Наконец, мне просто пришлось вручную удалить одну строку дублирования из таблицы SQLite.

2 голосов
/ 29 ноября 2016

Хотя столбцы могут быть помечены как primary_key, убедитесь, что это также применяется на уровне базы данных (например, когда база данных была создана каким-либо другим инструментом). В MySQL это означает, что они PRIMARY KEY, а не только KEY.

В моем случае было 2 столбца, отмеченных как primary_key (составной), но было несколько строк, содержащих одинаковые (предположительно) уникальные id.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...