Очевидно, использование ORM и Core в тандеме возможно , но я не смог найти какого-либо твердого объяснения стратегии для этого.
Вот класс использования:
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
следует сохранить с помощью ORM . data
, который будет большим массивом NumPy (или аналогичным типом), должен быть сохранен через Core .
Существует промежуточная таблица 'data_set'
, которая существует с целью отношения «многие к одному» между DataHolder
и данными. Это позволяет наборам данных существовать независимо в некоторой библиотеке. (Единственная цель этой таблицы - генерировать идентификаторы для новых наборов данных.)
Фактическое постоянство было бы достигнуто через класс, который реализует некоторые слушатели, такие как следующие.
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'
. В случае отката данные, добавленные через Core, не будут извлекаться из базы данных так же, как данные, связанные с ORM.
Есть ли другой, лучший способ манипулировать этим поведением, кроме прослушивания 'pending_to_transient'
? Это может вызвать проблемы в случае, когда два разных DataHolder
ссылаются на один и тот же набор данных: один DataHolder
может выполнить откат, удалив набор данных из базы данных, так что другой DataHolder
больше не сможет его использовать.