--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 6484
+
+ Enhanced the bind resolution rules for :meth:`_orm.Session.execute` so that
+ when a non-ORM statement such as an :func:`_sql.insert` construct
+ nonetheless is built against ORM objects, to the greatest degree possible
+ the ORM entity will be used to resolve the bind, such as for a
+ :class:`_orm.Session` that has a bind map set up on a common superclass
+ without specific mappers or tables named in the map.
clause = mapper.persist_selectable
if clause is not None:
+ plugin_subject = clause._propagate_attrs.get(
+ "plugin_subject", None
+ )
+
+ if plugin_subject is not None:
+ for cls in plugin_subject.mapper.class_.__mro__:
+ if cls in self.__binds:
+ return self.__binds[cls]
+
for obj in visitors.iterate(clause):
if obj in self.__binds:
return self.__binds[obj]
import sqlalchemy as sa
+from sqlalchemy import delete
from sqlalchemy import ForeignKey
+from sqlalchemy import insert
from sqlalchemy import inspect
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import table
from sqlalchemy import testing
from sqlalchemy import true
+from sqlalchemy import update
+from sqlalchemy.orm import aliased
from sqlalchemy.orm import backref
from sqlalchemy.orm import mapper
from sqlalchemy.orm import relationship
select(self.tables.concrete_sub_table)
)
is_(session.get_bind(clause=stmt), base_class_bind)
+
+ @testing.combinations(
+ (insert,),
+ (update,),
+ (delete,),
+ (select,),
+ )
+ def test_clause_extracts_orm_plugin_subject(self, sql_elem):
+ ClassWMixin = self.classes.ClassWMixin
+ MixinOne = self.classes.MixinOne
+ base_class_bind = Mock()
+
+ session = self._fixture({MixinOne: base_class_bind})
+
+ stmt = sql_elem(ClassWMixin)
+ is_(session.get_bind(clause=stmt), base_class_bind)
+
+ cwm_alias = aliased(ClassWMixin)
+ stmt = sql_elem(cwm_alias)
+ is_(session.get_bind(clause=stmt), base_class_bind)