Can't have a relation and its supporting column with the same name

Issue #1002 resolved
Former user created an issue

(original reporter: ged) This fails even when specifying allow_column_override to the mapper. The attached test case, produce the following traceback.

Traceback (most recent call last):
  File "test_one_to_many_same_name.py", line 50, in <module>
    session.flush()
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/session.py", line 766, in flush
    self.uow.flush(self, objects)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 233, in flush
    flush_context.execute()
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 445, in execute
    UOWExecutor().execute(self, tasks)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 930, in execute
    self.execute_save_steps(trans, task)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 948, in execute_save_steps
    self.execute_dependencies(trans, task, False)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 959, in execute_dependencies
    self.execute_dependency(trans, dep, False)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 942, in execute_dependency
    dep.execute(trans, isdelete)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py", line 895, in execute
    self.processor.process_dependencies(self.targettask, [for elem in self.targettask.polymorphic_tosave_elements if elem.state is not None](elem.state), trans, delete=False)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/dependency.py", line 337, in process_dependencies
    self._synchronize(state, child, None, False, uowcommit)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/dependency.py", line 377, in _synchronize
    self.syncrules.execute(source, dest, dest, child, clearkeys)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/sync.py", line 95, in execute
    rule.execute(source, dest, obj, child, clearkeys)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/sync.py", line 186, in execute
    self._raise_col_to_prop(True)
  File "/home/ged/devel/sqlalchemy/trunk/lib/sqlalchemy/orm/sync.py", line 134, in _raise_col_to_prop
    raise exceptions.UnmappedColumnError("Can't execute sync rule for destination column '%s'; mapper '%s' does not map this column.  Try using an explicit `foreign_keys` collection which does not include this column (or use a viewonly=True relation)." % (self.dest_column, self.dest_mapper))
sqlalchemy.exceptions.UnmappedColumnError: Can't execute sync rule for destination column 'parent.child'; mapper 'Mapper|Parent|parent' does not map this column.  Try using an explicit `foreign_keys` collection which does not include this column (or use a viewonly=True relation).

FWIW: it was first reported as an Elixir ticket: http://elixir.ematia.de/trac/ticket/39

I'm personally not sure whether this should be allowed or not, but I don't see the point of having the allow_column_override option if this particular use case is not allowed.

Comments (3)

  1. Mike Bayer repo owner

    allow_column_override means, "I don't care about this column being part of my mapping, just get rid of it". It's a less relevant flag now that we have "exclude_properties" and "include_properties", then again it still may be convenient for those cases when you just want to build relation names that may or may not step on columns you don't care about.

    However in this case, SQLAlchemy clearly needs access to the "parent_table.c.column" column in order to handle the relation, like the error indicates. So the correct pattern for this specific case is:

    mapper(Parent, parent_table,
        properties=dict(
            child_fkey=parent_table.c.child,
            child=relation(Child)
        ),
    )
    
  2. Former user Account Deleted

    (original author: ged) I know SA needs the column, but, since the user clearly indicates he doesn't care about this column (ie doesn't want to access it -- a user usually think in terms of what he does/doesn't need, what the underlying library does or need), we could somehow have that column still present in a private (not accessible from the outside) or anonymous way so that the relation can still work. This is the behavior I'd expect when "allow_column_override" is set.

  3. Mike Bayer repo owner

    as discussed on IRC i think the foreign key attribute on the class being automatically "hidden" is an implicit behavior that's better suited for Elixir itself - elixir would place a foreign key column_property() on the mapper using a private name (like underscored or similar).

    For SA, the "allow_column_override" flag is redundant versus "exclude_properties" and should probably be removed for that reason. Its usage has never been encouraged (except for its presence in the error message) and removing it will make it clearer that its up to the end user to re-target the same-named foreign key column. If you truly want a column ignored entirely, then using exclude_columns will make it clearer that thats what you're doing.

  4. Log in to comment