Automatic expiration of related properties (objects or collections), i.e. when the FK attribute changes. you know, this thing.

Issue #1939 wontfix
Former user created an issue

http://www.sqlalchemy.org/trac/ticket/1910#comment:5

When the sqla detects a change in an attribute which is included in the relationship() join, it can automatically expire the property of that relationship.

Bear in mind, some joins are manually specified, so these wouldn't necessarily be fks. I think it is sufficient that if the attribute that is changing is included anywhere in the join, the expiration should take place. This leaves some flexibility for mapper joins that are manually specified.

Comments (18)

  1. Former user Account Deleted

    Mike, I implemented a limited case of this functionality with an AttributeExtension.
    def set(self,...) decides which relations to expire based on whether any properties exist with self's attribute name in (l.key for (l, r) in prop.local_remote_pairs).

    I have a question. It is possible that a part of the related object which we are about to expire has unflushed changes. It is also possible that autoflush has been disabled. Any thoughts on how you'd deal with these circumstances? I looked into session.is_modified(), but it doesn't detect a change in a related object, nor would attributes.get_history(obj, 'relatedproperty')...

    Thanks very much, as always, Kent

  2. Mike Bayer repo owner

    By "unflushed changes", are you referring to the case when the FK attributes have been changed, and there are also changes to the relationship() reference itself ? Well yes that's why I am in no hurry to implement this feature. If they have autoflush off, they modified relationship(), then they went and set the FKs to something that is in conflict with relationship, with this new change the FKs win - or better yet we could raise an error if changes are detected on the relationship. Why would attributes.get_history() not work for checking a pending change ?

  3. Former user Account Deleted

    Replying to zzzeek:

    By "unflushed changes", are you referring to the case when the FK attributes have been changed, and there are also changes to the relationship() reference itself ?

    Yes, exactly

    Well yes that's why I am in no hurry to implement this feature. If they have autoflush off, they modified relationship(), then they went and set the FKs to something that is in conflict with relationship, with this new change the FKs win - or better yet we could raise an error if changes are detected on the relationship.

    Yeah, that might be the best, my brick wall was even detecting it

    Why would attributes.get_history() not work for checking a pending change ?

    I suppose it ''could'', but I'd have to recursively check all it's relations for changes as well, wouldn't I? In other words, attributes.get_history(obj,'related') only tells me if 'related' has been changed to a new object, None, etc, but it doesn't tell me whether it ''itself'' has changes. Is there such a library function already written that searches the save/update cascade of a given object for changes?

  4. Mike Bayer repo owner

    I dont think you need to check if the related object "itself" has changes - we're only talking about the linkage between parent and child object. The two objects are still in the session and changes they have which are not related to that linkage are handled independently.

  5. Former user Account Deleted

    Replying to zzzeek:

    I dont think you need to check if the related object "itself" has changes - we're only talking about the linkage between parent and child object. The two objects are still in the session and changes they have which are not related to that linkage are handled independently.

    Oh good. Much simpler then.

  6. Mike Bayer repo owner

    If A has a collection of 8000 B objects, does the modification of A.id go out and search for all 8000 Bs in the session and reset their "a" reference? that makes the assignment of A.id very expensive.

  7. Former user Account Deleted

    Replying to zzzeek:

    If A has a collection of 8000 B objects, does the modification of A.id go out and search for all 8000 Bs in the session and reset their "a" reference? that makes the assignment of A.id very expensive. That's a good question. I admit, we aren't in the habit of changing primary keys very often so I haven't needed to address this. My simple version of this ticket for our project only expires related collections/objects that are connected when a foreign key changes. We nearly never change the primary key and the only case I can think of where we do, we are setting the relationship, not changing the foreign key. This will happen at the flush, right? But your point is the set shouldn't be so expensive.

    It's this kind of thing dissuading you from setting foreign keys in the first place, isn't it?

  8. Mike Bayer repo owner

    I'd like to add a feature to relationship expire_on_local_attrs. You hit local attrs on the object and a local relationship expires, that's it, there's no interception of attributes on the related objects. The latter is a lot more complicated.

  9. Former user Account Deleted

    I think that is essentially what I've got, but I do not expire if it is along the save-update cascade since I expect those related objects to be "hand set", not just loaded from the database. So, at least for someone with a use case similar to ours, a feature for the relationship would work well.

  10. Former user Account Deleted

    I only expire ''relationships'' that aren't along the save-update cascade (actually, I use merge cascade, but save-update is probably more appropriate). So I check the property's cascade before expiring, essentially.

  11. Mike Bayer repo owner

    this has been out there for six years, we have a recipe for someone who really wants to play with this, I don't see this as ever being committed to the ORM as it would create lots more complexity and support cases we can't take on.

  12. Log in to comment