On Sun, Aug 13, 2017 at 2:37 PM, Ronuk Raval <ronuk.ra...@gmail.com> wrote:
> On Sunday, August 13, 2017 at 1:35:47 PM UTC-4, Jonathan Vanasco wrote:
>>
>> When I've been unable to handle things like this with cascades (which you
>> already using), I use `session.flush(objects=SPECIFIC_OBJECTS_LIST)` to only
>> flush a single object.  That usually gets me out of these situations.
>
>
> Unfortunately, the code I'm working with is in a deeply nested callstack
> where the current transaction can be in all sorts of states. An arbitrary
> flush can lead to constraint violations and I'd have to change quite a bit
> of code to make it work.

The unit of work makes decisions about table and row ordering based on
dependencies between mappers, and dependencies between mappers are
indicated exclusively through the relationship() construct (also
inheritance, which doesn't apply here).    Usually,  I build a
relationship() and work with that, translating whatever the direct
manipulation of FK attributes is into something in terms of the
relationship.

However here, that's not really possible.   The closest thing this
resembles is that you are altering the "key" of A and the it would
cascade to "B" - the ORM assumes you need to use ON UPDATE CASCADE for
that kind of thing, which takes care of it, or if you are using
foreign keys that are deferred or non-enforcing, the ORM can cascade
the value but it would be doing it from A first then B which is the
opposite of what you want here.

ON UPDATE CASCADE can't be used here anyway because this is an odd use
of MATCH SIMPLE on the FK and where normally setting some of the
columns to NULL means you're no longer referencing some row elsewhere,
so the NULL does not cascade (PG's behavior, tried it, doesn't work).
 The use case I can find for MATCH SIMPLE seems to be that the FK
would no longer refer to a row that matches the whole constraint, like
the example in 
https://dba.stackexchange.com/questions/148530/what-would-i-use-a-match-simple-foreign-key-for
.

The use of NULL as a meaningful boolean value is possibly straying
outside of normal relational practice.   In particular it's not even
possible to make a relationship() that represents this because PG does
not seem to allow me to use the "IS" operator here, which would be
necessary for the NULL values to line up but it keeps throwing syntax
errors for things like "a.archived IS b.archived", not sure why.

Onto the workarounds:

The flush() as mentioned earlier per object can be linked to setting
the "archived" flag using a hybrid like this:

from sqlalchemy.ext.hybrid import hybrid_property

class B(Base):
    __tablename__ = 'b'

    _archived = sa.Column("archived", sa.Boolean, nullable=True)

    @hybrid_property
    def archived(self):
        return self._archived

    @archived.setter
    def archived(self, value):
        self._archived = value
        sa.orm.object_session(self).flush([self])

alternatively you can emit the UPDATE directly, so that no other
aspects of B are affected, and skip history events so that the B isn't
added to the flush unless something else changes:

    @archived.setter
    def archived(self, value):
        sa.orm.object_session(self).execute(
            self.__table__.update().values(archived=value)
        )
        sa.orm.attributes.set_committed_value(
            self, '_archived', value)

I'd go for the latter as that puts the UPDATE and manipulation of this
attribute in total stealth mode, not affecting or affected by anything
ORM-level.














>
> I'm not opposed to doing that work but would like to explore the possibility
> of making the unit of work UPDATE order match my expectations. If that's not
> possible then c'est la vie.
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to