Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
737 views
in Technique[技术] by (71.8m points)

python - How to use make_transient() to duplicate an SQLAlchemy mapped object?

I know the question how to duplicate or copy a SQLAlchemy mapped object was asked a lot of times. The answer always depends on the needs or how "duplicate" or "copy" is interpreted. This is a specialized version of the question because I got the tip to use make_transient() for that.

But I have some problems with that. I don't really know how to handle the primary key (PK) here. In my use cases the PK is always autogenerated by SQLA (or the DB in background). But this doesn't happen with a new duplicated object.

The code is a little bit pseudo.

import sqlalchemy as sa
from sqlalchemy.orm.session import make_transient

_engine = sa.create_engine('postgres://...')
_session = sao.sessionmaker(bind=_engine)()


class MachineData(_Base):
    __tablename__ = 'Machine'    
    _oid = sa.Column('oid', sa.Integer, primary_key=True)


class TUnitData(_Base):
    __tablename__ = 'TUnit'
    _oid = sa.Column('oid', sa.Integer, primary_key=True)
    _machine_fk = sa.Column('machine', sa.Integer, sa.ForeignKey('Machine.oid'))
    _machine = sao.relationship("MachineData")

    def __str__(self):
        return '{}.{}: oid={}(hasIdentity={}) machine={}(fk={})' 
        .format(type(self), id(self),
                self._oid, has_identity(self),
                self._machine, self._machine_fk)


if __name__ == '__main__':
    # any query resulting in one persistent object
    obj = GetOneMachineDataFromDatabase()

    # there is a valid 'oid', has_identity == True
    print(obj)

    # should i call expunge() first?

    # remove the association with any session
    # and remove its “identity key”
    make_transient(obj)

    # 'oid' is still there but has_identity == False
    print(obj)

    # THIS causes an error because the 'oid' still exsits
    # and is not new auto-generated (what should happen in my
    # understandings)
    _session.add(obj)
    _session.commit()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After makeing a object instance transient you have to remove its object-id. Without an object-id you can add it again to the database which generates a new object-id for it.

if __name__ == '__main__':
    # the persistent object with an identiy in the database
    obj = GetOneMachineDataFromDatabase()

    # make it transient
    make_transient(obj)
    # remove the identiy / object-id
    obj._oid = None
    # adding the object again generates a new identiy / object-id
    _session.add(obj)
    # this include a flush() and create a new primary key
    _session.commit()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...