Esiste un design migliore del riflesso per gestire un numero elevato di oggetti ORM?

1

Ecco uno scenario in cui ho riscontrato variazioni in molte occasioni.

Immagina un feed XML che visualizza i dati relativi a tre diversi tipi di eventi: concerti, giochi e film. Ognuno ha un diverso set di parametri. Vogliamo racchiudere queste informazioni e memorizzarle per i nostri scopi. Quindi creiamo un database che contiene dati applicativi e tre tabelle per questi dati che chiameremo event_concert, event_play ed event_movie. Attacchiamo un ORM in cima.

Ogni ora eseguiamo il polling del feed, alla ricerca di nuovi dati e al salvataggio nel nostro database. Poiché il nostro ORM crea oggetti tipizzati, ci sono essenzialmente due modi in cui possiamo farlo.

Per prima cosa, scrivi tre funzioni separate, una per ciascun tipo di oggetto, che creano e popolano l'oggetto necessario e lo inseriscono nel database. Questo è pulito e facilmente comprensibile. Ma è più codice da scrivere e non è necessariamente il migliore per la manutenzione, dal momento che si aggiungono nuove funzioni per gestire nuovi tipi di oggetto e c'è il rischio di duplicare il codice.

In secondo luogo, scrivi un singolo loop che usa le varie funzioni di reflection del contesto ORM per iterare sui tipi di oggetto (usando un prefisso fisso come event_ per riconoscerli), quindi scorre le proprietà per popolarle prima di salvare nel Db . Questo è complicato e difficile da capire, ma fatto bene dovrebbe essere un'opzione "fire-and-forget" che raccoglierà semi-automaticamente e gestirà nuovi tipi di oggetti con un minimo di confusione.

In questo esempio è facile andare con la prima opzione poiché ci sono solo tre oggetti da salvare. Ma cosa succede se ce ne sono cinque? O cinquanta? O più? Gestire all'improvviso tutti quegli oggetti diversi con le loro funzioni personalizzate non sembra più così attraente.

Esiste un altro approccio o modello di progettazione che raggiunge un risultato simile ed è sia pulito che in grado di gestire molti tipi di oggetto?

Ecco un esempio di cosa intendo in pseudocodice.

Se consideriamo gli oggetti come tipi diversi:

GetAndInsertConcerts();
GetAndInsertMovies():
GetAndInsertPlays();
// if we need a fourth object type, we'll need to add a new function

public void GetAndInsertConcerts()
{
    var xmlConcerts = GetObjectsFromXML("Concerts");

    foreach(var xmlConcert in xmlConcerts)
    {
        Event_Concert c = new Event_Concert(xmlConcert);
        repository.InsertAndSave(c);
    }
 }
 // the functions for plays and movies will repeat this structure

E il secondo approccio:

string[] eventTypes = repository.GetTablesStartingWithEvent();

foreach(string eventType in eventTypes)
{
    string xml = GetXmlForEventType(eventType);
    // BuildObjectFromXml function is reflection based, likely hard to code & to follow
    var obj = BuildObjectFromXml(xml);  
    repository.InsertAndSave(obj);
}

Vale la pena ripeterlo - il boilerplate nel primo approccio va bene se hai a che fare con una manciata di tipi di oggetti che non ti aspetti di cambiare. Ma scrivere funzioni ripetute "ottieni e salva" per un sacco di tipi di oggetti diversi sta diventando noioso.

    
posta Matt Thrower 17.01.2018 - 18:16
fonte

1 risposta

2

... done right it should be a fire-and-forget option that will semi-automatically pick up and deal with new object types with a minimum of fuss.

Davvero? Mi sembra che l'elefante nella stanza sia un disadattamento di impedenza.

Il tuo scenario ha due database: il primo che presumo appartenga a qualcun altro; puoi accedervi solo tramite XML esportato. Il secondo che possiedi e accedi con l'ORM. Se lo schema del primo database cambia, come si rileva la modifica? La strategia fire-and-forget sembra che possa danneggiare in modo silenzioso il tuo database o che inizi a generare eccezioni che non hai pianificato di gestire.

Il tuo ORM funziona tramite riflessione o codice generato. La tua domanda è come gestire il mapping dall'XML agli oggetti. Per la manutenibilità, la risposta è sicuramente che se il tuo ORM usa il riflesso, dovresti usare il reflection, e se il tuo ORM usa il codice generato, dovresti usare il codice generato. In questo modo il programmatore di manutenzione deve gestire meno incongruenze.

Ad ogni modo, utilizzerei uno schema per XML (ne scriverò uno da solo se il fornitore dei dati non ne fornisce uno) e aggiungo controlli in fase di compilazione e di runtime che lo schema di XML corrisponda allo schema di l'ORM, oltre a un controllo in fase di esecuzione, verifica che l'XML ricevuto corrisponda allo schema. In caso di disallineamento, si desidera ricevere una notifica: non eseguirò la compilazione nel controllo in fase di compilazione e mi invierò una e-mail nei controlli di runtime.

Infine, l'elenco dei tipi di oggetti da gestire dovrebbe essere in un file di configurazione. Ricostruirlo dal database significa che non puoi decidere di interrompere la gestione di un determinato tipo di evento senza perdere i dati esistenti.

    
risposta data 18.01.2018 - 12:37
fonte

Leggi altre domande sui tag