Чтение атрибутов отдельного объекта sqlalchemy вызывает DetachedInstanceError - PullRequest
0 голосов
/ 24 октября 2019

Я использую краткосрочные сеансы sqlalchemy для добавления объектов в базу данных sqlite. Несколько объектов переживают сеанс в отключенном состоянии только для чтения. К сожалению, доступ к атрибутам отдельного объекта вызывает исключение, если сеанс был закрыт. Вот упрощенный пример кода

from sqlalchemy import Column, String, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)

engine = create_engine('sqlite:///foo.db', echo=False)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

f = Foo(name='foo1')
print('state=transient : name=', f.name)
session.add(f)
print('state=pending : name=', f.name)
session.commit()
session.close()
print('state=detached : name=', f.name)
# output
state=transient : name= foo1
state=pending : name= foo1
Traceback (most recent call last):
  File "scratch_46.py", line 23, in <module>
    print('state=detached : name=', f.name)
  File "lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 282, in __get__
    return self.impl.get(instance_state(instance), dict_)
  File "lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 705, in get
    value = state._load_expired(state, passive)
  File "lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 660, in _load_expired
    self.manager.deferred_scalar_loader(self, toload)
  File "lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 913, in load_scalar_attributes
    "attribute refresh operation cannot proceed" % (state_str(state))
sqlalchemy.orm.exc.DetachedInstanceError: Instance <Foo at 0x7f266c758ac8> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)

Как ни странно, ошибка не выдается, если я выполню любой из этих

  • Чтение атрибута name между фиксациейи закрывать вызовы, когда объект находится в постоянном состоянии
  • Вычеркнуть объект из сеанса и оставить сеанс открытым. Все еще отключенное состояние, но я могу получить доступ к атрибуту.

Могу ли я прочитать атрибуты отсоединенного объекта? Есть ли способ, чтобы объекты безопасно пережили переходные сеансы? Я прочитал предлагаемую ссылку в выходных данных, но в основном она говорит об отношениях родитель / потомок.

Я создал проблему в репозитории sqlalchemy, потому что сначала я думал, что это ошибка,но теперь я не уверен в этом.

1 Ответ

0 голосов
/ 24 октября 2019

Вкопался в это еще и обнаружил, что я получаю бит по умолчанию, равным expire_on_commit, равным true в сеансе. Когда это включено, вызов commit завершает срок действия объекта, что вынуждает sqlalchemy перезагружать его при следующем чтении атрибута. Если это задерживается до окончания сессии, то атрибуты не могут быть извлечены.

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

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