Regression: r3681 orm/session.py _save_impl change breaks logic requiring multiple saves

Issue #856 resolved
Former user created an issue

My code handles two interdependent objects from two tables that each have serial primary keys. The logic is essentially

intermediary = Intermediary() session.save(intermediary) session.flush() # this gives the intermediary an id ob = Version() ob.id = intermediary.id session.save(ob) session.flush() # this gives the version an id intermediary.current_version = ob.version_id session.save(intermediary) #XXX now raises InvalidRequestError session.flush() # this sets the current version id on the intermediary table

This worked fine with 0.4.0, but as of r3681 this raises with an InvalidRequestError: Instance '%s' is already persistent

Attached patch simply restores the previous test if obj._instance_key not in self.identity_map: before raising the exception.

Comments (1)

  1. Mike Bayer repo owner

    that patch exactly reverses the change in 206c0b9792b02a0d77d92e679952cb2d0465cede, when in fact, save() is only supposed to be used for transient objects, not persistent. also, the additional call to save() in your example is entirely unnecessary; any changes to intermediary will be flushed automatically since its already present in the session. If intermediary were not present in the session, you'd use the update() method to place an already persistent object in. Alternatively, to place objects in the session without worrying if they're transient or persistent, use save_or_update(). This is the reason save() has been made more strict, so that people don't get confused over its usage.

    as I've mentioned on the mailing list, im strongly considering replacing the whole set of methods with just a single add() method since i think thats much clearer as to what's actually going on; the current method names are derived from Hibernate and I don't think they are buying us much.

    intermediary = Intermediary()
    session.save(intermediary)
    session.flush() # this gives the intermediary an id
    ob = Version()
    ob.id = intermediary.id
    session.save(ob)
    session.flush() # this gives the version an id
    intermediary.current_version = ob.version_id
    session.flush() # will save everything present in the session, including intermediary
    
  2. Log in to comment