<p dir="auto"><strong>Migrated issue, originally created by Denis Otkidach (<a href="https://github.com/ods">@ods</a>)</strong></p>
<p dir="auto">Test case:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
 
 
Base = declarative_base()
 
 
class DocLink(Base):
    __tablename__ = 'DocLink'
    id = Column(Integer, primary_key=True)
    block_id = Column(ForeignKey('DocLinkBlock.id', ondelete='CASCADE'),
                      nullable=False)
    block = relationship('DocLinkBlock',
                         primaryjoin='DocLink.block_id==DocLinkBlock.id')
    ref_url = Column(String(250), nullable=True)
    ref_doc_id = Column(ForeignKey('Doc.id'))
    ref_doc = relationship('Doc', primaryjoin='DocLink.ref_doc_id==Doc.id')
 
 
class DocLinkBlock(Base):
    __tablename__ = 'DocLinkBlock'
    id = Column(Integer, primary_key=True)
    doc_id = Column(ForeignKey('Doc.id', ondelete='CASCADE'), nullable=False)
    doc = relationship('Doc')
    links = relationship(DocLink, cascade='all, delete-orphan')
 
 
class Doc(Base):
    __tablename__ = 'Doc'
    id = Column(Integer, primary_key=True)
    link_blocks = relationship(DocLinkBlock, cascade='all, delete-orphan')
 
 
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
 
ref_doc = Doc(id=1)
session.add(ref_doc)
session.commit()
 
doc = Doc(
    id=2,
    link_blocks=[
        DocLinkBlock(
            id=1,
            links=[
                DocLink(
                    id=1,
                    ref_url='url',
                    ref_doc=ref_doc,
                ),
            ],
        ),
    ],
)
session.add(doc)
session.commit()
assert doc.link_blocks[0].links[0].ref_url=='url'
assert doc.link_blocks[0].links[0].ref_doc is ref_doc
 
doc.link_blocks = [
    DocLinkBlock(
        id=1,
        links=[
            DocLink(
                id=1,
                ref_url=None,
                ref_doc=None,
            ),
        ],
    ),
]
session.commit()
assert doc.link_blocks[0].links[0].ref_url is None
assert doc.link_blocks[0].links[0].ref_doc is None # Fails"><pre class="notranslate"><code class="notranslate">from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
 
 
Base = declarative_base()
 
 
class DocLink(Base):
    __tablename__ = 'DocLink'
    id = Column(Integer, primary_key=True)
    block_id = Column(ForeignKey('DocLinkBlock.id', ondelete='CASCADE'),
                      nullable=False)
    block = relationship('DocLinkBlock',
                         primaryjoin='DocLink.block_id==DocLinkBlock.id')
    ref_url = Column(String(250), nullable=True)
    ref_doc_id = Column(ForeignKey('Doc.id'))
    ref_doc = relationship('Doc', primaryjoin='DocLink.ref_doc_id==Doc.id')
 
 
class DocLinkBlock(Base):
    __tablename__ = 'DocLinkBlock'
    id = Column(Integer, primary_key=True)
    doc_id = Column(ForeignKey('Doc.id', ondelete='CASCADE'), nullable=False)
    doc = relationship('Doc')
    links = relationship(DocLink, cascade='all, delete-orphan')
 
 
class Doc(Base):
    __tablename__ = 'Doc'
    id = Column(Integer, primary_key=True)
    link_blocks = relationship(DocLinkBlock, cascade='all, delete-orphan')
 
 
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
 
ref_doc = Doc(id=1)
session.add(ref_doc)
session.commit()
 
doc = Doc(
    id=2,
    link_blocks=[
        DocLinkBlock(
            id=1,
            links=[
                DocLink(
                    id=1,
                    ref_url='url',
                    ref_doc=ref_doc,
                ),
            ],
        ),
    ],
)
session.add(doc)
session.commit()
assert doc.link_blocks[0].links[0].ref_url=='url'
assert doc.link_blocks[0].links[0].ref_doc is ref_doc
 
doc.link_blocks = [
    DocLinkBlock(
        id=1,
        links=[
            DocLink(
                id=1,
                ref_url=None,
                ref_doc=None,
            ),
        ],
    ),
]
session.commit()
assert doc.link_blocks[0].links[0].ref_url is None
assert doc.link_blocks[0].links[0].ref_doc is None # Fails
</code></pre></div>
<p dir="auto">There is no such problem when <code class="notranslate">DocLinkBlock.links</code> is updated directly (no nested collections).</p>
<p dir="auto"><strong>Migrated issue, originally created by Denis Otkidach (<a href="https://github.com/ods">@ods</a>)</strong></p>
<p dir="auto">New object with the same ID as existing one implicitly merged via cascade rules has old value of relationship property after the commit when the new value is None.</p>
<p dir="auto">In short:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="doc.doc_links = [DocLink(id=doc_link_id, link=None)]
session.commit()
assert doc.doc_links[0].link is None  # fails"><pre class="notranslate"><code class="notranslate">doc.doc_links = [DocLink(id=doc_link_id, link=None)]
session.commit()
assert doc.doc_links[0].link is None  # fails
</code></pre></div>
<p dir="auto">Full test is attached (test3 is the test case that fails).</p>
<hr>
<p dir="auto">Attachments: <a href="../wiki/imported_issue_attachments/3060/sa_merge_relation.py">sa_merge_relation.py</a> | <a href="../wiki/imported_issue_attachments/3060/3060.patch">3060.patch</a></p>