2010-08-09 23 views
10

Ho iniziato a pensare a tenere traccia delle modifiche nel grafico di oggetti complessi in un'applicazione disconnessa. Ho già trovato diverse soluzioni, ma vorrei sapere se esiste qualche pratica migliore o quale soluzione utilizzi e perché? Ho passato la stessa domanda a MSDN forum ma ho ricevuto solo una risposta. Mi piacerebbe avere più risposte per imparare dall'esperienza di altri sviluppatori.Tracciamento delle modifiche nel grafico di oggetti complessi

Questa domanda è correlata a .NET, quindi per le risposte con dettagli di implementazione preferisco le risposte relative al mondo .NET ma penso che questo sia lo stesso su altre piattaforme.

Il problema teorico nel mio caso è definita in multi architettura a strati (non necessariamente n livelli al momento) come segue:

  • Strato di repository utilizzando ORM per affrontare persistenza (ORM no al momento, ma probabilmente sarà Entity Framework 4.0 o NHibernate).
  • Insieme di classi pure (persistente ignorante = POCO che equivale a POJO nel mondo Java) che rappresenta gli oggetti del dominio. I repository persistono in quelle classi e le restituiscono come risultati di query.
  • Insieme di servizi di dominio che funzionano con entità di dominio.
  • Livello facciata che definisce il gateway per la business logic. Internamente utilizza repository, servizi di dominio e oggetti di dominio. Gli oggetti di dominio non sono esposti - ogni metodo di facciata utilizza set di oggetti di trasferimento dati specializzati per parametro e valore di ritorno. È responsabilità di ciascun metodo di facciata trasformare l'entità del dominio in DTO e viceversa.
  • Applicazione Web moderna che utilizza il layer di facciata e DTO: io chiamo questa applicazione disconnessa. In generale, la progettazione può cambiare in futuro, in modo che il livello di facciata venga spostato dal livello del servizio Web e l'applicazione Web consumerà i servizi => passaggio a 3 livelli (Web, business logic, database).

Supponiamo ora che uno degli oggetti del dominio sia Ordine con dettagli dell'ordine (righe) e Ordini correlati. Quando il cliente richiede l'ordine per la modifica, può modificare l'ordine, aggiungere, rimuovere o modificare i dettagli dell'ordine e aggiungere o rimuovere gli ordini correlati. Tutte queste modifiche vengono eseguite sui dati nel browser Web: javascript e AJAX. Quindi tutte le modifiche vengono inviate in un'unica ripresa quando il client preme il pulsante Salva. La domanda è come gestire questi cambiamenti? Lo strumento Deposito e ORM deve sapere quali entità e relazioni sono state modificate, inserite o eliminate. Ho terminato con due soluzioni "migliori":

  1. Memorizza lo stato iniziale del DTO in campo nascosto (in caso contrario alla sessione). Quando si riceve una richiesta di salvataggio delle modifiche, creare un nuovo DTO basato sui dati ricevuti e sul secondo DTO basato sui dati persistenti. Unisci questi due e tiene traccia delle modifiche. Invia DTO unito al layer facciata e utilizza le informazioni ricevute sulle modifiche per impostare correttamente il grafico delle entità. Ciò richiede del tracciamento manuale delle modifiche nell'oggetto dominio, in modo che le informazioni sulle modifiche possano essere configurate da zero e successivamente trasferite al repository. Questo è il punto di cui non sono molto soddisfatto.

  2. Non tenere traccia delle modifiche nel DTO. Quando si ricevono i dati modificati nel livello facciata creare entità modificate e caricare lo stato effettivo dal repository (in genere query aggiuntiva al database - questo è il punto che non sono molto soddisfatto) - unire queste due entità e tenere traccia automaticamente delle modifiche per proxy di entità fornito dallo strumento ORM (Entity framework 4.0 e NHibernate lo consentono). È necessaria particolare attenzione per la gestione della concorrenza perché lo stato effettivo non deve essere lo stato iniziale.

Cosa ne pensi?Che cosa mi consiglia?

So che alcune di queste sfide possono essere evitate utilizzando la memorizzazione nella cache su alcuni livelli dell'applicazione, ma è qualcosa che non voglio utilizzare al momento.

Il mio interesse per questo argomento va ancora oltre. Ad esempio, supponiamo che l'applicazione vada all'architettura a 3 livelli e il client (l'applicazione web) non verrà scritto in .NET = Le classi DTO non possono essere riutilizzate. Monitorare i cambiamenti su DTO sarà molto più difficile perché richiederà ad altri team di sviluppo di implementare correttamente il meccanismo di tracciamento nei loro strumenti di sviluppo.

Credo che questi problemi debbano essere risolti in molte applicazioni, per favore condividi la tua esperienza.

risposta

3

Si tratta di responsabilità.

(Non sono sicuro se questo è il tipo di risposta che stai cercando - fammi sapere se non è così posso aggiornarlo).

Quindi abbiamo più livelli in un sistema: ognuno è responsabile di un compito diverso: accesso ai dati, interfaccia utente, logica aziendale, ecc. Quando architettiamo un sistema in questo modo siamo (tra le altre cose) cercando di fare futuro cambia facilmente rendendo ciascun componente responsabile di un compito, in modo che possa concentrarsi su quel compito e farlo bene. Rende anche più semplice modificare il sistema con il passare del tempo e il cambiamento è necessario.

Pensieri simili devono essere in mente quando si considera il DTO - "come tenere traccia dei cambiamenti?" per esempio. Ecco come mi avvicino: il BL è responsabile della gestione delle regole e della logica; data la natura stateless del web (che è dove faccio la maggior parte del mio lavoro) non sto semplicemente monitorando lo stato di un oggetto e guardando esplicitamente i cambiamenti. Se un utente sta trasferendo i dati indietro (per essere salvato/aggiornato) passerò tutto il lotto indietro senza preoccuparsi di ciò che è stato cambiato.

Da un lato questo potrebbe sembrare inefficiente, ma poiché la quantità di dati non è vasta, non è un problema; Sul rovescio della medaglia, ci sono meno "parti mobili" meno possono andare storte in quanto il processo è molto più semplice.

Come passare i dati indietro? -

  • Uso DTO (o forse POCO sarebbe più preciso); quando scambio dati tra BL e DAL (tramite interfacce/DI) i dati vengono scambiati come DTO (o insieme di essi). In particolare, sto usando una struct per una singola istanza e una collezione di queste strutture per più.

  • I DTO sono definiti in una classe comune che ha pochissime dipendenze.

  • Provo deliberatamente a limitare il numero di DTO di una creazione per un oggetto specifico (come "Ordine") - ma allo stesso tempo ne creerò di nuovi se c'è una buona ragione. In genere avrò un DTO "grasso" che contiene la maggior parte/tutti i dati disponibili per quell'oggetto, probabilmente ne avrò uno molto più snello che è stato progettato per essere usato in collezioni (per liste, ecc.). In entrambi i casi questi DTO sono in puro stato per restituire informazioni per "leggere". Devi tenere a mente le responsabilità: quando BL richiede dei dati, di solito non sta cercando di scrivere i dati nello stesso momento; quindi il fatto che il DTO sia "di sola lettura" riguarda più la conformità a un'interfaccia e un'architettura pulite rispetto a una regola aziendale.

  • Definisco sempre DTO separati per Inserimento e aggiornamento, anche se condividono esattamente gli stessi campi. In questo modo, il peggio che può accadere è la duplicazione di qualche codice trival - invece di avere dipendenze e più casi di riuso per districarsi.

Infine, non confondere il modo in cui il DAL funziona con l'interfaccia utente; Lascia che gli ORM facciano le loro cose, solo perché memorizzano i dati in un determinato modo non significa che sia l'unico modo.

La cosa più importante è specificare interfacce significative tra i livelli.

Gestire ciò che è cambiato è il lavoro del BL; lascia che l'interfaccia utente funzioni in un modo che è meglio per i tuoi utenti e lascia che la BL capisca come vuole affrontarlo, e il DAL (tramite la tua bella interfaccia pulita con) fa esattamente ciò che viene detto.

+1

Ciao, grazie per la risposta molto buona. Mi piace. È molto vicino alla mia architettura, tranne che nel mio caso sto usando DTO tra UI e BL e oggetti/entità di dominio tra BL e DAL. Comprendo la tua spiegazione, l'unico punto che mi manca è la risposta alla domanda principale: come tenere traccia dei cambiamenti nel grafico di oggetti complessi? Ricevi DTO e devi in ​​qualche modo scoprire cosa è cambiato. Se il DTO è un oggetto semplice, non è necessario tracciarlo, ma per quanto riguarda DTO che contiene una raccolta di altri DTO? Devi sapere cosa è cambiato in quella raccolta. –

+0

RE cambiamenti nell'oggetto Grafico - Mi aspetto Ci sono schemi di progettazione che gestiranno questo, ma non riesco a ricordare nessuno in cima alla mia testa - mi viene in mente Momento, altrimenti forse un modello guidato dagli eventi? –

+0

Nel modello ASP.NET tradizionale, le pagine tendono a essere create da zero ogni volta (e quindi si sta caricando in tutti i dati indipendentemente da cosa è cambiato), e se si stanno persistendo i dati nel viewstate si tende a trattarli come "i dati" - quindi non sono stato nella posizione di voler cercare cambiamenti specifici nel modo che stai suggerendo (?). L'altro approccio è basato su AJAX, ma questo è simile.Il modello di osservatore potrebbe anche essere di interesse. –

3

la nostra architettura è molto simile alla tua, ma utilizzando un client Silverlight contenente gli stessi oggetti di dominio (che non è esatto - il codice è condiviso) su client e server. I punti chiave della nostra architettura è in breve

  • Il cliente ha il modello di dominio e le modifiche vengono monitorati utilizzando il mio quadro di monitoraggio implementato (usa AOP in modo che posso usare pocos sul lato client, io no conoscere un framework per questo e voglio che il modello di dominio sia persistente ignorante)
  • Questo intero modello è memorizzato in una sorta di repository remoto sul client. Quando salviamo queste modifiche, viene estratto un albero delle modifiche (dal mio framework di tracciamento delle modifiche) e tradotto in DTO (esattamente DataContracts ma non importa) utilizzando gli assemblatori. I DTO hanno un flag di stato di tracciamento (nuovo, modificato, cancellato).
  • Sul lato server (il livello di servizio è implementato dai servizi Web WCF) i DTO vengono convertiti in oggetti di dominio e collegati all'ORM (NHibernate nel nostro caso). A causa di questo processo di attaccamento ho bisogno dello stato di tracciamento. Le modifiche aggiuntive possono essere apportate e mantenute tramite ORM

Attualmente è difficile allegare grafici complessi all'ORM, ma spero che il motivo sia che non abbiamo molta esperienza nell'utilizzo di NHibernate.

Non abbiamo ancora finito, ma sembra essere promettente.

Per l'accesso ai dati, abbiamo provato a utilizzare i servizi dati WCF. Ma non penso che li useremo perché un requisito sta usando DataContract. Ciò porta a una traduzione da query LINQ basate su DataContract a query LINQ basate su oggetti di dominio. Ciò non è pratico e troppo difficile da implementare se il modello di dominio e i contratti di dati differiscono molto (ciò si verifica in alcune iterazioni).

Qualche considerazione?

Problemi correlati