2014-10-02 14 views
11

Vorrei rivedere alcuni dei miei modelli SQLAlchemy esistenti in un datastore di sola aggiunta; append-only significa che l'oggetto viene aggiornato solo con le istruzioni INSERT, non utilizzando le istruzioni UPDATE o DELETE.Come implementare un modello con versione solo append in SQLAlchemy

Le istruzioni UPDATE e DELETE verranno sostituite con un altro INSERT che incrementa la versione. Ci sarebbe una bandiera is_deleted invece di DELETE, verrebbe creata una nuova versione con is_deleted=True:

id | version | is_deleted | name  | description ... 
---- --------- ------------ ----------- --------------- 
    1 |  1 |   F | Fo  | Text text text. 
    1 |  2 |   F | Foo  | Text text text. 
    2 |  1 |   F | Bar  | null 
    1 |  3 |   T | Foo  | Text text text.   

Inoltre,

  • dovranno essere riscritto per solo il massimo numero di versione per tutte le istruzioni SELECT ogni id, come descritto in questa domanda: PostgreSQL - fetch the row which has the Max value for a column
  • Tutti gli indici (univoci) devono essere riscritti per essere univoci dalla chiave primaria "id", poiché ciascun ID può essere presente più di una volta.

so come risolvere la maggior parte di questi problemi, ma sto lottando con i ganci di eventi in SQLAlchemy che avrebbe gestire certe cose che devono essere fatto su aggiornamento & eliminare.

La documentazione di SQLAlchemy contiene già alcuni esempi di base per il controllo delle versioni. L'esempio versioned rows si avvicina a ciò che desidero, ma non gestisce (1) l'eliminazione e (2) le relazioni con le chiavi esterne.

(1) Cancellazione. So che c'è un campo session.deleted, e vorrei scorrere su di esso in un modo simile a come session.dirty viene ripetuto nell'esempio versioned_rows.py, ma come faccio a rimuovere l'elemento dall'elenco da eliminare & creare un nuovo elemento?

(2) L'esempio sopra menzionato riguarda solo una relazione genitore-figlio e il modo in cui funziona (scadendo la relazione) sembra richiedere un codice personalizzato per ciascun modello. (2.1) C'è un modo per renderlo più flessibile? (2.2) è possibile configurare SQLAlchemy's relationship() per restituire l'oggetto con max (versione) per una data chiave esterna?

+1

Il termine che stai cercando è "soft-delete". Non so davvero SQLAlchemy, ma forse questo ti aiuterà. Personalmente probabilmente lo farei con i trigger sul lato del database. –

+0

Grazie - Ho trovato questo su soft delete, che aiuta con la prima parte della mia domanda http://stackoverflow.com/questions/23198801/sqlalchemy-using-aliased-in-query-with-custom-primaryjoin-relationship Utilizzo del database i trigger non sono un'opzione per me perché il mio modello cambia frequentemente e i trigger non sono gestiti bene dagli strumenti di migrazione come alambicco. – lyschoening

+1

Domanda curiosa, mi piacerebbe anche vedere alcuni esempi di come gestirlo. Per quanto riguarda il collegamento al massimo (versione), il modo migliore è probabilmente di non avere un numero di versione rispetto alla versione Head in modo da poter partecipare direttamente all'ultimo record (versione == Nessuno). I dati devono essere nella stessa tabella? Mi chiedo solo se il sistema di oggetti versioning (che crea una seconda tabella, blah_history) potrebbe semplificare le cose http://docs.sqlalchemy.org/en/latest/orm/examples.html#versioning-objects. Gestisce anche le eliminazioni in quanto l'intera cronologia delle versioni è disponibile nella tabella secondaria. –

risposta

1

Una cosa utile che sarebbe agnostica dello strumento ORM potrebbe essere "invece di" trigger. Ad esempio, è possibile rilevare un evento di aggiornamento precedente e aprire un numero di versione con i dati appena aggiornati.

Per postgresql sono dettagliate here.

Ovviamente, è necessario apportare modifiche al modello (su PK, ecc.).

Inoltre, vale la pena studiare gli impatti delle prestazioni, poiché è probabile che si debba avere una query ricorsiva per recuperare la "versione più recente" (attraverso un livello di visualizzazione o in alchimia sql dove clausole/ecc.)

0

Per quanto possa sembrare strano, potrebbe essere meglio utilizzare un diverso tipo di database. Sei a conoscenza di Datomic?. Una delle differenze fondamentali tra un RDBMS tradizionale e questo tipo di sistema è che non esiste un aggiornamento sul posto, ovvero come un RDBMS aggiorna i file sul disco. Invece, tutto è versionato e puoi tornare indietro attraverso tutte le versioni precedenti del database per ogni modifica a ogni singola risorsa. Inoltre, è possibile visualizzare facilmente lo stato dell'intero database in un determinato momento, passando semplicemente il tempo di interesse come parametro.Ci sono molti altri vantaggi interessanti e consiglio vivamente di dare un'occhiata ad alcuni dei discorsi di Rich Hickey su di esso, ad esempio this one. È decisamente un approccio fondamentalmente diverso rispetto a quello che stai attualmente tentando, ma bisogna considerare se quel tentativo sarà perseguitato combattendo contro gli strumenti in ogni fase del processo, usandoli in un modo che in realtà non erano progettato (RDBMS, ORM, gestore di migrazione, ...). Invece, potresti spingere quella complessità su un livello e lasciare che un diverso tipo di DB lo gestisca per te.

Problemi correlati