diff options
-rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 8 | ||||
-rw-r--r-- | test/orm/inheritance/concrete.py | 26 | ||||
-rw-r--r-- | test/orm/unitofwork.py | 20 |
3 files changed, 47 insertions, 7 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 99e93df5d..172b99558 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -368,7 +368,7 @@ class Mapper(object): for mapper in list(_mapper_registry): if not mapper.compiled: mapper.__initialize_properties() - + _new_mappers = False return self finally: @@ -526,10 +526,10 @@ class Mapper(object): # mark these as "read only" properties which are refreshed upon # INSERT/UPDATE self._readonly_props = util.Set([ - self._columntoproperty[col] for col in all_cols if + self._columntoproperty[col] for col in self._columntoproperty if not hasattr(col, 'table') or col.table not in self._cols_by_table ]) - + # if explicit PK argument sent, add those columns to the primary key mappings if self.primary_key_argument: for k in self.primary_key_argument: @@ -1190,7 +1190,7 @@ class Mapper(object): # expire readonly attributes readonly = state.unmodified.intersection([ - p.key for p in chain(*[m._readonly_props for m in mapper.iterate_to_root()]) + p.key for p in mapper._readonly_props ]) if readonly: diff --git a/test/orm/inheritance/concrete.py b/test/orm/inheritance/concrete.py index ffc95ac05..b6d31a715 100644 --- a/test/orm/inheritance/concrete.py +++ b/test/orm/inheritance/concrete.py @@ -1,7 +1,9 @@ import testenv; testenv.configure_for_tests() from sqlalchemy import * from sqlalchemy.orm import * +from sqlalchemy.orm import exc as orm_exc from testlib import * +from sqlalchemy.orm import attributes class ConcreteTest(ORMTest): def define_tables(self, metadata): @@ -133,16 +135,34 @@ class ConcreteTest(ORMTest): concrete=True, polymorphic_identity='hacker') session = create_session() - session.save(Manager('Tom', 'knows how to manage things')) - session.save(Engineer('Jerry', 'knows how to program')) - session.save(Hacker('Kurt', 'Badass', 'knows how to hack')) + tom = Manager('Tom', 'knows how to manage things') + jerry = Engineer('Jerry', 'knows how to program') + hacker = Hacker('Kurt', 'Badass', 'knows how to hack') + session.add_all((tom, jerry, hacker)) session.flush() + + # ensure "readonly" on save logic didn't pollute the expired_attributes + # collection + assert 'nickname' not in attributes.instance_state(jerry).expired_attributes + assert 'name' not in attributes.instance_state(jerry).expired_attributes + assert 'name' not in attributes.instance_state(hacker).expired_attributes + assert 'nickname' not in attributes.instance_state(hacker).expired_attributes + def go(): + self.assertEquals(jerry.name, "Jerry") + self.assertEquals(hacker.nickname, "Badass") + self.assert_sql_count(testing.db, go, 0) + session.clear() assert set([repr(x) for x in session.query(Employee).all()]) == set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"]) assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"]) assert set([repr(x) for x in session.query(Engineer).all()]) == set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"]) + # because we are concrete, are intentionally repeating integer ids across + # tables, and have told the "Engineer" mapper to load polymorphically, + # this cannot work: + self.assertRaises(orm_exc.MultipleResultsFound, session.query(Engineer).filter(Engineer.employee_id==1).one) + def test_relation(self): class Employee(object): def __init__(self, name): diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py index f0ab709af..371335b07 100644 --- a/test/orm/unitofwork.py +++ b/test/orm/unitofwork.py @@ -992,6 +992,11 @@ class ColumnPropertyTest(_base.MappedTest): Column('a', String(50)), Column('b', String(50)) ) + + Table('subdata', metadata, + Column('id', Integer, ForeignKey('data.id'), primary_key=True), + Column('c', String(50)), + ) def setup_mappers(self): class Data(_base.BasicEntity): @@ -1009,6 +1014,21 @@ class ColumnPropertyTest(_base.MappedTest): m = mapper(Data, data) m.add_property('aplusb', column_property(data.c.a + literal_column("' '") + data.c.b)) self._test() + + @testing.resolve_artifact_names + def test_with_inheritance(self): + class SubData(Data): + pass + mapper(Data, data, properties={ + 'aplusb':column_property(data.c.a + literal_column("' '") + data.c.b) + }) + mapper(SubData, subdata, inherits=Data) + + sess = create_session() + sd1 = SubData(a="hello", b="there", c="hi") + sess.add(sd1) + sess.flush() + self.assertEquals(sd1.aplusb, "hello there") @testing.resolve_artifact_names def _test(self): |