SQLAlchemy получает элементы из карты идентичности не только по первичному ключу
Можно ли использовать пару полей не из первичного ключа для извлечения элементов (уже выбранных ранее) из карты идентификации? Например, я часто запрашиваю таблицу (external_id, platform_id)
пара, которая является уникальным ключом, но не первичным ключом. И я хочу опустить ненужные запросы SQL в таких случаях.
2 ответа
Краткий обзор identity_map и get():
Карта идентификаторов сохраняется для жизненного цикла SQLAlchemy session
объект, т.е. в случае веб-службы или RESTful API session
Жизненный цикл объекта не более одного request
(рекомендуемые).
От: http://martinfowler.com/eaaCatalog/identityMap.html
Карта идентификации хранит записи обо всех объектах, которые были считаны из базы данных в одной бизнес-транзакции. Всякий раз, когда вам нужен объект, вы сначала проверяете карту идентичности, чтобы увидеть, есть ли у вас ее.
В ORM SQLAlchemy есть этот специальный метод запроса get()
сначала смотрит в identity_map
используя pk (только допустимый аргумент) и возвращает объект из карты идентичности, фактически выполняя SQL
запрос и попадание в базу данных.
Из документов:
get(ident)
Вернуть экземпляр на основе заданного идентификатора первичного ключа или
None
если не найден
get()
отличается тем, что обеспечивает прямой доступ к идентификационной карте владельцаSession
, Если указанный идентификатор первичного ключа присутствует в локальной карте идентификаторов, объект возвращается непосредственно из этой коллекции, и SQL не выдается, если только объект не был отмечен как полностью истекший. Если нет, выполняется SELECT для определения местоположения объекта.
Только get()
использует identity_map
- официальные документы:
Он в некоторой степени используется в качестве кэша, поскольку он реализует
identity map
шаблон и хранит объекты, привязанные к ихprimary key
, Однако он не выполняет никакого кеширования запросов. Это значит, если вы говоритеsession.query(Foo).filter_by(name='bar')
, даже еслиFoo(name='bar')
прямо там, на карте идентичности, сессия не имеет представления об этом. Он должен выдать SQL в базу данных, вернуть строки обратно, а затем, когда он увидит первичный ключ в строке, он может просмотреть локальную карту идентификации и увидеть, что объект уже существует. Это только когда ты говоришьquery.get({some primary key})
что сеанс не должен выдавать запрос.
PS Если вы запрашиваете, не используя pk
ты не ударяешь identity_map
на первом месте.
Несколько актуальных вопросов SO, полезно прояснить концепцию:
Принудительное использование sqlalchemy ORM get() вне карты идентификации
Можно получить доступ ко всей карте идентичности последовательно:
for obj in session.identity_map.values():
print(obj)
Чтобы получить объект по произвольным атрибутам, вам нужно сначала отфильтровать тип объекта, а затем проверить ваши атрибуты.
Это не поиск в постоянное время, но может предотвратить ненужные запросы.
Существует аргумент, что объекты могли быть изменены другим процессом, и карта идентификации не содержит текущего состояния, но этот аргумент недействителен: если уровень изоляции транзакции равен read committed
(или меньше) - и это часто бывает, данные ВСЕГДА могли быть изменены сразу после завершения запроса.