Giugno 2016
Volume 31 Numero 6
Il presente articolo è stato tradotto automaticamente.
Cutting Edge - Creazione di operazioni CRUD cronologiche, parte 2
Da Dino Esposito | Giugno 2016
Vista concettuale, un cronologici creazione, lettura, aggiornamento, eliminazione (CRUD) è la classica CRUD estesa con un parametro aggiuntivo: una data. Un CRUD cronologici consente di aggiungere, aggiornare ed eliminare record da un database e consente di eseguire query sullo stato del database in un determinato punto nel tempo. Un CRUD cronologici offre alle applicazioni un'infrastruttura incorporata per avanzate funzionalità di reporting e analisi di business intelligence.
Nell'articolo del mese scorso (msdn.com/magazine/mt703431), ho presentato la base teorica di sistemi CRUD cronologici. In questo articolo fornirò una dimostrazione pratica.
Presentare lo Scenario di esempio
Ai fini di questo articolo, vedrà un sistema di prenotazione semplice. Richiedere, ad esempio, il sistema di di che un'azienda utilizza internamente per consentire ai dipendenti sale riunioni libro. Al termine, tale software è un normale CRUD in cui viene creato un nuovo record per riservare uno slot. Lo stesso record viene aggiornato se la riunione viene spostata in un momento diverso o eliminato se viene annullata la riunione.
Se si codifica tale sistema di prenotazione come un normale CRUD, conoscere lo stato più recente del sistema, ma perse le informazioni sulle discussioni aggiornate ed eliminate. Si tratta davvero un problema? Dipende. È probabilmente non sia un problema se si osserva semplicemente gli effetti delle riunioni sull'azienda effettivo. Tuttavia, se si sta cercando modi per migliorare le prestazioni complessive dei dipendenti, quindi un CRUD cronologici che tiene traccia degli aggiornamenti ed eliminazioni di record potrebbero indicare che le riunioni troppe volte vengono spostate o annullate e che potrebbe essere il segno di-ottimale processi interni o atteggiamento non valida.
Figura 1 presenta un'interfaccia utente realistica per un sistema di prenotazione di chat. Il database sottostante è un database di SQL Server con un paio di tabelle collegate: Le chat e prenotazioni.
Figura 1, l'interfaccia utente front-end di un sistema di prenotazione
L'applicazione di esempio è progettata come un'applicazione ASP.NET MVC. Quando l'utente fa clic per inserire la richiesta, un metodo del controller interviene ed elabora le informazioni registrate. Il seguente frammento di codice offre un'idea chiara del codice gestisce la richiesta sul lato server:
[HttpPost]
public ActionResult Add(RoomRequest room)
{
service.AddBooking(room);
return RedirectToAction("index", "home");
}
Il metodo appartiene a una classe BookingController e delega a una classe di servizio lavoro inserito il compito di organizzare il lavoro effettivo. Un aspetto interessante di implementazione del metodo è che reindirizza alla pagina anteriore Figura 1 dopo la creazione della prenotazione. Non esiste alcuna visualizzazione esplicita viene creato come risultato dell'operazione Aggiungi prenotazione. Questo è un effetto secondario di scelta di un'architettura di comando Query Responsibility Segregation (CQRS). Il comando Aggiungi prenotazione viene inserito per il back-end; modifica lo stato del sistema e questo è tutto. L'applicazione di esempio utilizzasse AJAX per registrare, non avremmo avuto dover aggiornare nulla e il comando avremmo avuto un funzionamento autonomo senza alcun collegamento visibile nell'interfaccia utente.
La differenza principale tra un classico CRUD e un CRUD cronologici è che quest'ultimo tiene traccia di tutte le operazioni che modificano lo stato del sistema dopo l'inizio. Per pianificare un CRUD cronologici, è consigliabile pensare come comandi assegnata al sistema e di un meccanismo per individuare i comandi delle operazioni aziendali. Ogni comando modifichi lo stato del sistema e un CRUD cronologici tiene traccia di ogni stato che raggiunge il sistema. Qualsiasi stato raggiunto viene registrato come un evento. Un evento è la descrizione di un elemento semplice e non modificabile che si è verificati. Dopo aver creato l'elenco degli eventi, è possibile creare diverse proiezioni di dati nella parte superiore, il più popolare dei quali è semplicemente lo stato corrente di entità coinvolti.
In un'applicazione, gli eventi derivano direttamente dall'esecuzione di comandi dell'utente o indirettamente da altri comandi o input esterno. In questo scenario di esempio, si richiedono all'utente di fare clic su un pulsante per inviare una richiesta di prenotazione.
Elaborazione del comando
Di seguito è riportata una possibile implementazione del metodo AddBooking del controller dell'applicazione:
public void AddBooking(RoomRequest request)
{
var command = new RequestBookingCommand(request);
var saga = new BookingSaga();
var response = saga.AddBooking(command);
// Do something based on the outcome of the command
}
La classe RoomRequest è un oggetto di trasferimento dei dati semplice compilato dal livello di associazione di ASP.NET MVC da dati inseriti. La classe RequestBookingCommand, ma archivia i parametri di input necessari per eseguire il comando. In un semplice scenario di questo tipo, le due classi quasi coincidono. Come è necessario elaborare il comando? Figura 2 vengono presentati i passaggi chiave tre dell'elaborazione di un comando.
Figura 2 la catena di passaggi di base per eseguire un comando
Il gestore è un componente che riceve il comando e lo elabora. Un gestore può essere richiamato mediante una chiamata in memoria diretta dal codice del servizio di lavoro o è possibile configurare un bus centrale, come illustrato di seguito:
public void AddBooking(RoomRequest request)
{
var command = new RequestBookingCommand(request);
// Place the command on the bus for
// registered components to pick it up
BookingApplication.Bus.Send(command);
}
Un bus potrebbe riportare un paio di vantaggi. Uno è che è possibile gestire facilmente gli scenari in cui potrebbero essere interessati più gestori nello stesso comando. Un altro vantaggio è che un bus potrebbe essere configurato per essere uno strumento di messaggistica affidabile che garantisce il recapito del messaggio nel tempo e la risoluzione dei problemi di connettività possibili. Inoltre, un bus può essere solo il componente che offre la possibilità di eseguire il comando.
Il gestore può essere un semplice componente occasionale che inizia e termina con la stessa richiesta oppure può essere un flusso di lavoro a esecuzione prolungata che accetta ore o giorni per completare e può essere sospesa in attesa di approvazione risorse umane in un determinato momento. I gestori che non sono semplici attività One-Off gli esecutori sono spesso chiamati saghe.
In generale, utilizzare un bus o una coda se si dispone di requisiti specifici in termini di scalabilità e affidabilità. Se cercano solo la creazione di un CRUD cronologico anziché un classico CRUD, probabilmente non occorre utilizzare un bus. Che si utilizzi un bus o non, a un certo punto il comando potrebbe raggiungere il relativo gestore One-Off o con esecuzione prolungata. Il gestore è progettato per eseguire tutte le attività sono previsti. La maggior parte delle attività sono costituiti da operazioni di base in un database.
Il comando di registrazione
In un classico CRUD, la scrittura delle informazioni in un database comporterebbe l'aggiunta di un record che viene disposto i valori passati. In una prospettiva storica CRUD, tuttavia, il record appena aggiunto rappresenta l'evento creato di prenotazioni. L'evento creato di prenotazioni è un componente indipendente e non modificabile di informazioni che include un identificatore univoco per l'evento, un timestamp, un nome e un elenco di argomenti specifici dell'evento. Gli argomenti di un evento creato in genere includono tutte le colonne che vorrebbe per un record di prenotazione appena aggiunto in una tabella di prenotazioni classico. Gli argomenti dell'evento updated, invece, sono limitati ai campi che vengono effettivamente aggiornati. Successivamente, tutti gli eventi aggiornati potrebbero non hanno lo stesso contenuto. Infine, gli argomenti di un evento deleted sono limitati ai valori che identificano in modo univoco la prenotazione.
Qualsiasi operazione di un CRUD cronologici sono necessari due passaggi:
- Registrare l'evento e i dati correlati.
- Verificare che lo stato corrente del sistema è immediatamente in modo rapido e queryable.
In questo modo, lo stato corrente del sistema è sempre disponibile e aggiornati e tutte le operazioni che ha portato ad esso sono anche disponibili per l'ulteriore analisi. Si noti che lo "stato corrente del sistema" è l'unico stato semplicemente visualizzati in un sistema CRUD classico. Per essere efficace nel contesto di un semplice sistema CRUD, il passaggio di registrazione dell'evento e l'aggiornamento dello stato del sistema avviene in modo sincrono e all'interno della stessa transazione, come illustrato nella Figura 3.
Figura 3 registrazione di un evento e l'aggiornamento del sistema
using (var tx = new TransactionScope())
{
// Create the "regular" booking in the Bookings table
var booking = _bookingRepository.AddBooking(
command.RoomId, ...);
if (booking == null)
{
tx.Dispose();
return CommandResponse.Fail;
}
// Track that a booking was created
var eventToLog = command.ToEvent(booking.Id);
eventRepository.Store(eventToLog);
tx.Complete();
return CommandResponse.Ok;
}
Come elementi, ogni volta che si aggiunge, modifica o elimina un record di prenotazione che l'elenco globale di prenotazioni di mantenere aggiornate durante conoscere l'esatta sequenza degli eventi che ha causato lo stato corrente. Figura 4 vengono illustrate le due tabelle di SQL Server coinvolte nello scenario di esempio e il relativo contenuto dopo un inserimento e aggiornamento.
Figura 4 prenotazioni e tabelle LoggedEvents Side by Side
La tabella elenca le prenotazioni tutte le prenotazioni distinte trovate nel sistema e per ognuno restituisce lo stato corrente. La tabella LoggedEvents Elenca tutti gli eventi per i vari prenotazioni nell'ordine in che cui sono stati registrati. Ad esempio, la prenotazione 54 sia stato creato in una determinata data e modificato in seguito. Nell'esempio, la colonna di carico nell'immagine archivia il flusso di serializzazione JSON del comando eseguito.
Utilizzando gli eventi registrati nell'interfaccia utente
Si supponga che un utente autorizzato che desidera visualizzare i dettagli di una prenotazione in sospeso. Probabilmente l'utente verrà visualizzato per la prenotazione da un elenco di calendario o tramite una query basate sul tempo. In entrambi i casi, i fatti della prenotazione fondamentali, ovvero quando, per quanto tempo e che, sono già noti e i dettagli di visualizzazione potrebbe anche essere di grande utilità. Può effettivamente essere utile, tuttavia, se è possibile visualizzare l'intera cronologia della prenotazione, come illustrato nella Figura 5.
Figura 5 utilizzo degli eventi registrati nell'interfaccia utente
Leggendo tramite gli eventi registrati, è possibile compilare un modello di visualizzazione che include un elenco di stati per la stessa entità di aggregazione: 54 # di prenotazione. Nell'applicazione di esempio, quando l'utente fa clic per visualizzare i dettagli della prenotazione viene visualizzata un finestra popup modale e alcuni JSON viene scaricato in background. L'endpoint che restituisce JSON è illustrato di seguito:
public JsonResult BookingHistory(int id)
{
var history = _service.History(id);
var dto = history.ToJavaScriptSlotHistory();
return Json(dto, JsonRequestBehavior.AllowGet);
}
Il metodo di cronologia del servizio di lavoro esegue la maggior parte delle operazioni di seguito. La parte principale di questa attività esegue una query tutti gli eventi correlati all'ID di prenotazione specificato:
var events = new EventRepository().All(aggregateId);
foreach (var e in events)
{
var slot = new SlotInfo();
switch (e.Action)
{
:
}
history.Changelist.Add(slot);
}
Il ciclo tramite gli eventi registrati, viene aggiunto un oggetto appropriato per l'oggetto di trasferimento dei dati da restituire. Alcuni trasformazione eseguita nel ToJavaScriptSlotHistory rende più rapido e semplice visualizzare il delta tra i due stati consecutivi nel modulo visualizzato Figura 5.
È notevole, tuttavia, che consente di registrazione degli eventi anche all'interno di un CRUD per tali miglioramenti utili nell'interfaccia utente, il valore più grande risiede nel fatto ora sapere tutto quello che si è mai verificato all'interno del sistema e può elaborare i dati per estrarre qualsiasi proiezione personalizzata dei dati che potrebbe essere necessario un certo punto. Ad esempio, si potrebbe creare una statistica dell'aggiornamento di analisti forniti per la conclusione che l'intero processo di richiesta di sale riunioni non funziona all'interno della società perché troppo spesso libro, persone e quindi update o delete. È possibile rilevare facilmente verso il basso è la situazione delle prenotazioni di una data specifica semplicemente l'esecuzione di query di eventi registrati fino a quel momento e calcolare lo stato delle operazioni successive. In breve, un CRUD cronologici apre un mondo di possibilità per le applicazioni completamente nuovo.
Avvolgendo
CRUD cronologici è semplicemente un modo efficiente in continua evoluzione di semplici applicazioni CRUD. Tuttavia, questa discussione trattati termini altisonanti e modelli che sono molto più logica di business possibili, ad esempio CQRS, eventi di approvvigionamento, bus e le code e basata su messaggi. Se in questo articolo è risultata utile, è consigliabile si torni indietro e leggere il luglio 2015 (msdn.com/magazine/mt238399) e agosto 2015 (msdn.com/magazine/mt185569) colonne. Alla luce di questo esempio, si potrebbero trovare gli articoli ancora più!
Dino Espositoè l'autore di "Microsoft .NET: Architettura delle applicazioni per l'azienda"(Microsoft Press, 2014) e"Moderne applicazioni Web con ASP.NET"(Microsoft Press, 2016). Technical evangelist per .NET e a piattaforme Android al JetBrains e spesso come relatore a eventi del settore in tutto il mondo, Esposito condivide la sua visione del software in software2cents@wordpress.com e su Twitter: @despos.
Grazie all'esperto tecnico Microsoft seguente per la revisione di questo articolo: Jon Arne Saeteras