Cascade_backrefs Behavior Deprecated For Removal In 2.0

58 views
Skip to first unread message

Thorsten von Stein

unread,
Apr 5, 2022, 1:02:37 PM4/5/22
to sqlalchemy
I'm currently trying to get my applications ready for SQLAlchemy 2.0. A change that has forces code changes in numerous places is the removal of the automatic addition of new instances to the session upon establishing a relationship with an object already in the session. In the explanation of the change this is described "not generally a desirable behavior". However, it is a behavior on which I currently completely rely for persisting new instances. Since, in my system, new instances are always connected to a parent object, I never had to add any object explicitly to a session, and so session objects are currently basically absent from the application code.

Here are my questions:
- Will there be a way to turn back on this behavior in 2.0? I would be thrilled if there was, but I fear the answer is negative.
- How would you recommend dealing with the situation: Either passing sessions as additional parameters to any function or method that creates new objects, or, calling the session maker within each such function? In particular, is there any particular downside to the latter?


Mike Bayer

unread,
Apr 5, 2022, 2:58:33 PM4/5/22
to noreply-spamdigest via sqlalchemy


On Tue, Apr 5, 2022, at 1:02 PM, Thorsten von Stein wrote:
I'm currently trying to get my applications ready for SQLAlchemy 2.0. A change that has forces code changes in numerous places is the removal of the automatic addition of new instances to the session upon establishing a relationship with an object already in the session. In the explanation of the change this is described "not generally a desirable behavior". However, it is a behavior on which I currently completely rely for persisting new instances. Since, in my system, new instances are always connected to a parent object, I never had to add any object explicitly to a session, and so session objects are currently basically absent from the application code.

Here are my questions:
- Will there be a way to turn back on this behavior in 2.0? I would be thrilled if there was, but I fear the answer is negative.

the whole behavior is done using event handlers which is public API.  so you could set up the attributeevents.append() [1] and attributeevents.set() [2] event handlers to add the local side to the session:

from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import object_session
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
from sqlalchemy.orm import configure_mappers

Base = declarative_base()


class A(Base):
    __tablename__ = "a"

    id = Column(Integer, primary_key=True)
    data = Column(String)
    bs = relationship("B", backref="a")


class B(Base):
    __tablename__ = "b"
    id = Column(Integer, primary_key=True)
    a_id = Column(ForeignKey("a.id"))
    data = Column(String)

configure_mappers()

@event.listens_for(B.a, "set")
def set_(target, newvalue, oldvalue, initiator):
    sess = object_session(newvalue)
    if target not in sess:
        sess.add(target)


e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)

a1 = A()
s.add(a1)
s.commit()


b1 = B(a=a1)
assert b1 in s.new




there's an example of how to add new attribute events automatically at https://docs.sqlalchemy.org/en/14/_modules/examples/custom_attributes/listen_for_events.html , though you'd want to alter it to test each new attribute for being an "object" based attribute.


- How would you recommend dealing with the situation: Either passing sessions as additional parameters to any function or method that creates new objects, or, calling the session maker within each such function? In particular, is there any particular downside to the latter?


For a given chain of methods that are working in the same transaction I would have a Session that's passed around to all of them, likely via some contextual object, so that they can all ensure the object is added to the persistence context as needed.      calling a sessionmaker inside of each method implies you're building a new session/transaction inside of each method which means each method would need to commit its own transaction, did you mean the scoped_session()?  scoped_session is an option as well if you are already using that, though I favor an explicit session/context being passed around as this allows functions and methods to explicitly state that they need to take place within this particular kind of context.






--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
 
 
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.

Thorsten von Stein

unread,
Apr 5, 2022, 3:09:57 PM4/5/22
to sqlalchemy
Thanks, Mike. Yes, I am using the scoped session. Am I understanding you correctly that, when using the scoped session, there is no penalty when calling the sessionmaker repeatedly, but that you still prefer passing around sessions as parameters for transparency reasons?

Mike Bayer

unread,
Apr 5, 2022, 3:58:25 PM4/5/22
to noreply-spamdigest via sqlalchemy


On Tue, Apr 5, 2022, at 3:09 PM, Thorsten von Stein wrote:
Thanks, Mike. Yes, I am using the scoped session. Am I understanding you correctly that, when using the scoped session, there is no penalty when calling the sessionmaker repeatedly, but that you still prefer passing around sessions as parameters for transparency reasons?

the scoped_session doesn't call "sessionmaker" repeatedly; it calls it once per thread, until you say scoped_session.remove().  it's a thread local registry for a persistent Session object.

I do prefer passing sessions around as global registries tend to be forgotten and contribute to the "implicitness" of a program.


Reply all
Reply to author
Forward
0 new messages