SQLAlchemy策略:ORM +核心用于包含大量数据的类

时间:2019-04-25 22:53:47

标签: python sqlalchemy

显然use of ORM and Core in tandem is possible,但我无法找到对此策略的可靠解释。

这是用例类:

class DataHolder(Base):
    __tablename__ = 'data_holder'

    id = Column(Integer, primary_key=True)
    dataset_id = Column(Integer, ForeignKey('data_set.id'))
    name = Column(String)

    _dataset_table = Table('data_set', Base.metadata,
        Column('id', Integer, primary_key=True),
    )

    _datarows_table = Table('data_rows', Base.metadata,
        Column('id', Integer, primary_key=True),
        Column('dataset_id', None, ForeignKey('data_set.id')),
        Column('row', Integer),
        Column('col_0', Integer),
        Column('col_1', Integer),
        Column('col_2', Integer),
    )

    def __init__(self, name=None, data=None):
        self.name = name
        self.data = data

    def _pack_info(self):
        # Return __class__ and other info needed for packing.

    def _unpack_info(self):
        # Return info needed for unpacking.

name应该通过the ORM保留。 data应该是大型的NumPy数组(或类似类型),应通过the Core保留。

存在一个中间表'data_set',其目的是DataHolder与数据之间的many-to-one关系。这允许数据集独立地存在于某些库中。 (此表的唯一目的是为新数据集生成ID。)

实际持久性将通过实现一些侦听器的类来实现,例如以下类。

class PersistenceManager:
    def __init__(self):
        self.init_db()
        self.init_listeners()

    def init_db(self):
        engine = create_engine('sqlite:///path/to/database.db')
        self.sa_engine = engine
        self.sa_sessionmaker = sessionmaker(bind=engine)
        Base.metadata.create_all(engine)

    def init_listeners(self):
        @event.listens_for(Session, 'transient_to_pending')
        def pack_data(session, instance):
            try:
                pack_info = instance._pack_info()
                # Use Core to execute INSERT for bulky data.
            except AttributeError:
                pass
        @event.listens_for(Session, 'loaded_as_persistent')
        def unpack_data(session, instance):
            try:
                unpack_info = instance._unpack_info()
                # Use Core to execute SELECT for bulky data.
            except AttributeError:
                pass

    def persist(self, obj):
        session.add(obj)

    def load(self, class_, spec):
        obj = session.query(class_).filter_by(**spec).all()[-1]
        return obj

    def session_scope(self):
        session = self.sa_sessionmaker()
        try:
            yield session
            session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()

这个想法是,每当DataHolder被保留时,其数据也将在相同(或几乎相同)的时间被保留。

监听'transient_to_pending'(用于“打包”)和'loaded_as_persistent'(用于“解包”)事件可以简化保存和加载。但是,似乎也应该注意监听'pending_to_transient'事件。对于rollback,通过Core添加的数据不会以与ORM相关的数据相同的方式从数据库中拉回。

除了听'pending_to_transient'之外,还有另一种更好的方法来操纵这种行为吗?在两个不同的DataHolder引用同一数据集的情况下,这可能会引起问题:一个DataHolder可以回滚,从数据库中删除该数据集,从而另一个DataHolder不再使用它。

0 个答案:

没有答案