Progettazione: come evitare l'interruzione della compatibilità a causa delle modifiche al database

7

Questo è il mio scenario, ho questa interfaccia:

public interface hitTheDataBase
{
    public void insertMe(String [] values);
    public void modifyMe(String [] values);
    public DataTable selectMe();
}

E ho queste due classi che implementano l'interfaccia:

public Class hitSqlServer implements hitTheDatabase
{
    public void insertMe(String [] values)
    {
         executes insert into table_in_sqlServerBD (col1, col2) values(values[0], values[1])
    }
    public void modifyMe(String [] values)
    {
         executes update table_in_sqlServerBD set col1 = values[0], col2 =  values[1] where rowid = values[3]
    }

    public DataTable selectMe()
    {
         executes select col1, col2 from table_in_sqlServerBD
    }
}

public Class hitSqLite implements hitTheDatabase
{
    public void insertMe(String [] values)
    {
         executes insert into table_in_sqLite (col1, col2) values(values[0], values[1])
    }
    public void modifyMe(String [] values)
    {
         executes update table_in_sqlLite set col1 = values[0], col2 =  values[1] where rowid = values[3]
    }

    public DataTable selectMe()
    {
         executes select col1, col2 from table_in_sqLite
    }
}

Questo fa parte di un'applicazione beta attualmente in esecuzione negli ambienti di test e di produzione (!), ma verrà aggiornata regolarmente a causa di correzioni di bug non correlate con le operazioni del database. Gli aggiornamenti vengono semplicemente eseguiti tramite la disinstallazione e la reinstallazione.

Ora ho un nuovo requisito per una situazione angolare molto specifica che richiederà una nuova colonna "col3" da aggiungere alla tabella, e dovrò inserire, selezionare e aggiornare i valori anche in quella colonna. Il problema è che non voglio rompere la compatibilità con i database esistenti in cui il software è già in esecuzione.

Stavo pensando di codificare una terza classe che implementa l'interfaccia HitTheDataBase, una classe helper per verificare se "col3" esiste e fare qualcosa del tipo:

hitTheDataBase hitMe = !helperclass.col3Exists() ? new hitSqlServer() : new hitSqlServerWithCol3();

È un buon approccio? Mi sembra buono, tranne perché dovrò modificare il codice nelle classi che usano quelle che "colpiscono il database". Inoltre dovrò controllare costantemente se esiste il valore di col3 per mostrarlo nella GUI e lasciare che l'utente lo modifichi.

    
posta Broken_Window 10.03.2016 - 21:35
fonte

3 risposte

10

Quando vengono distribuiti gli aggiornamenti software, c'è qualche ragione per cui non è possibile aggiornare anche lo schema? Una modifica al software che richiede una modifica allo schema del database implica che lo schema debba cambiare sul sistema di destinazione.

La compatibilità con versioni precedenti di uno schema di database è in genere qualcosa da evitare e l'hacking del Data Access Layer per supportare più versioni dello schema sembra un odore di design.

Una soluzione più pulita è garantire che il codice sia sempre in esecuzione rispetto alla versione dello schema per la quale è stato scritto il codice. Ciò non solo renderà il codice più facile da scrivere e manterrà il codice più pulito, ma renderà anche il codice più facile da testare. È possibile includere gli script di migrazione come parte del processo di installazione / disinstallazione per l'aggiornamento e il rollback.

Il tuo schema include qualsiasi tipo di tabella delle versioni? In caso contrario, è necessario aggiungere una tabella di versione dello schema al più presto. Il controllo delle versioni dello schema è di vitale importanza per gli aggiornamenti e i rollback.

Per un lungo periodo di tempo è probabile che si finisca con un sacco di script di aggiornamento dello schema che dovranno essere eseguiti in un ordine specifico durante l'installazione / disinstallazione. Un meccanismo di controllo delle versioni dello schema è fondamentale per garantire che gli aggiornamenti ei rollback dello schema vengano eseguiti correttamente.

D'altra parte, se non si dispone di un meccanismo per mantenere il proprio schema in linea con la propria versione del software, allora il livello di accesso ai dati potrebbe esplodere in modo esponenziale a causa di un numero crescente di "hack" preservare la retrocompatibilità; e sarai gravato da un sovraccarico sempre crescente di test di regressione ogni volta che cambi qualcosa nel tuo schema.

    
risposta data 10.03.2016 - 23:37
fonte
1

Questo è ciò che accade se lo schema del database non corrisponde a una versione dell'applicazione. Qualsiasi applicazione che ottiene il nuovo codice col3, dovrebbe avere il database aggiornato con esso.

Se hai intenzione di verificare se una colonna esiste in una tabella, devi solo crearla durante l'aggiornamento alla versione più recente.

    
risposta data 10.03.2016 - 23:39
fonte
1

Direi di no.

Questo tipo di [infinito] "se, ma, forse, a meno che, eccetto" la logica non guidi solo alla follia e, forse ancora più importante, rallenti l'applicazione, perché tutti questi "controlli" vengono eseguiti a corsa -tempo.

Suggerirei versioning che lo schema cambi e memorizzi quella versione [numero] da qualche parte nel database (come parte dell'avanzamento dell'aggiornamento).

Crea una versione della tua classe di accesso ai dati per ogni versione del database.

In fase di esecuzione, interrogare il database per la versione dello schema e creare un'istanza della classe "giusta" basata su tale.

    
risposta data 11.03.2016 - 13:03
fonte

Leggi altre domande sui tag