.. changelog::
:version: 1.1.0b3
+ .. change::
+ :tags: change, orm
+ :tickets: 3749
+
+ Removed a warning that dates back to 0.4 which emits when a same-named
+ relationship is placed on two mappers that inherits via joined or
+ single table inheritance. The warning does not apply to the
+ current unit of work implementation.
+
+ .. seealso::
+
+ :ref:`change_3749`
+
+
.. change::
:tags: bug, sql
:tickets: 3745
:ticket:`3630`
+.. _change_3749:
+
+Same-named relationships on inheriting mappers no longer warn
+--------------------------------------------------------------
+
+When creating two mappers in an inheritance scenario, placing a relationship
+on both with the same name would emit the warning
+"relationship '<name>' on mapper <name> supersedes the same relationship
+on inherited mapper '<name>'; this can cause dependency issues during flush".
+An example is as follows::
+
+ class A(Base):
+ __tablename__ = 'a'
+ id = Column(Integer, primary_key=True)
+ bs = relationship("B")
+
+
+ class ASub(A):
+ __tablename__ = 'a_sub'
+ id = Column(Integer, ForeignKey('a.id'), primary_key=True)
+ bs = relationship("B")
+
+
+ class B(Base):
+ __tablename__ = 'b'
+ id = Column(Integer, primary_key=True)
+ a_id = Column(ForeignKey('a.id'))
+
+
+This warning dates back to the 0.4 series in 2007 and is based on a version of
+the unit of work code that has since been entirely rewritten. Currently, there
+is no known issue with the same-named relationships being placed on a base
+class and a descendant class, so the warning is lifted. However, note that
+this use case is likely not prevalent in real world use due to the warning.
+While rudimentary test support is added for this use case, it is possible that
+some new issue with this pattern may be identified.
+
+.. versionadded:: 1.1.0b3
+
+:ticket:`3749`
+
.. _change_3653:
Hybrid properties and methods now propagate the docstring as well as .info
(self.key, self.parent.class_.__name__,
self.parent.class_.__name__))
- # check for conflicting relationship() on superclass
- if not self.parent.concrete:
- for inheriting in self.parent.iterate_to_root():
- if inheriting is not self.parent \
- and inheriting.has_property(self.key):
- util.warn("Warning: relationship '%s' on mapper "
- "'%s' supersedes the same relationship "
- "on inherited mapper '%s'; this can "
- "cause dependency issues during flush"
- % (self.key, self.parent, inheriting))
-
def _get_cascade(self):
"""Return the current cascade setting for this
:class:`.RelationshipProperty`.
"(a AS a_1 JOIN c AS c_1 ON a_1.id = c_1.id) ON c_1.bid = b.id "
"JOIN (a AS a_2 JOIN d AS d_1 ON a_2.id = d_1.id) "
"ON d_1.cid = c_1.id"
- )
\ No newline at end of file
+ )
+
+
+class SameNameOnJoined(fixtures.MappedTest):
+
+ run_setup_mappers = 'once'
+ run_inserts = None
+ run_deletes = None
+
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ 'a', metadata,
+ Column(
+ 'id', Integer, primary_key=True,
+ test_needs_autoincrement=True)
+ )
+ Table(
+ 'a_sub', metadata,
+ Column('id', Integer, ForeignKey('a.id'), primary_key=True)
+ )
+ Table(
+ 'b', metadata,
+ Column('id', Integer, primary_key=True,
+ test_needs_autoincrement=True),
+ Column('a_id', Integer, ForeignKey('a.id'))
+
+ )
+
+ @classmethod
+ def setup_mappers(cls):
+ class A(cls.Comparable):
+ pass
+
+ class ASub(A):
+ pass
+
+ class B(cls.Comparable):
+ pass
+
+ mapper(A, cls.tables.a, properties={
+ 'bs': relationship(B, cascade="all, delete-orphan")
+ })
+
+ mapper(ASub, cls.tables.a_sub, inherits=A, properties={
+ 'bs': relationship(B, cascade="all, delete-orphan")
+ })
+
+ mapper(B, cls.tables.b)
+
+ def test_persist(self):
+ A, ASub, B = self.classes('A', 'ASub', 'B')
+
+ s = Session(testing.db)
+
+ s.add_all([
+ A(bs=[B(), B(), B()]),
+ ASub(bs=[B(), B(), B()])
+ ])
+ s.commit()
+
+ eq_(s.query(B).count(), 6)
+
+ for a in s.query(A):
+ eq_(len(a.bs), 3)
+ s.delete(a)
+
+ s.commit()
+
+ eq_(s.query(B).count(), 0)