merge is calling expire on pending/transient instances

Issue #1789 resolved
Mike Bayer repo owner created an issue
  1. InstanceState.expire_attributes should raise if self.key is None

  2. InstanceState should gain has_identity and we should lose orm.util._state_has_identity so this check always available

  3. ColumnProperty.merge should be checking has_identity before expiring

    #!python from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.orm import attributes from sqlalchemy import exc

    metadata = MetaData() foo = Table('foo', metadata, Column('id', Integer, primary_key=True), Column('data', String) ) engine = create_engine('sqlite://', echo=True) metadata.create_all(engine)

    class Foo(object): pass

    mapper(Foo, foo) session = sessionmaker()()

    f1 = Foo() session.add(f1)

    state = attributes.instance_state(f1) attributes.instance_state(f1).expire_attributes(state.dict, 'data')

    try: print f1.data except exc.UnboundExecutionError: # should not be hitting the DB print "raised !"

    session.bind = engine f2 = Foo() f2.id = 2 f2 = session.merge(f2)

    session.bind = None try: f2.data except exc.UnboundExecutionError: # should not be hitting the DB print "raised !"

also see related test in #1681

Comments (2)

  1. Mike Bayer reporter

    6ea6673376609ce6a5e26f9f20425cffee96bcd8. Interestingly, disallowing state.expire_attributes() on a "pending" state is not at all an option here, since expiration occurs within the flush() process for states that have just become persistent, but don't yet have their key assigned. In some cases the loader is even fired off before the flush finishes and hence before state.key is assigned. The key assignment currently happens at the end in most cases in _register_newly_persistent() since we bookkeep for some "key switch" scenarios there after all SQL has been emitted.

  2. Log in to comment