Quanto lontano dovrebbe un'entità occuparsi dei valori delle sue proprietà da solo?

6

Consideriamo il seguente esempio di una classe, che è un'entità che sto usando attraverso Entity Framework.

- InvoiceHeader
    - BilledAmount (property, decimal)
    - PaidAmount (property, decimal)
    - Balance (property, decimal)

Sto cercando di trovare l'approccio migliore per mantenere aggiornato il saldo, in base ai valori delle altre due proprietà (BilledAmount e PaidAmount).

Sono combattuto tra due pratiche qui:

  1. Aggiornamento della quantità di saldo ogni volta che BilledAmount e PaidAmount vengono aggiornati (tramite i loro setter)
  2. Avere un metodo UpdateBalance () che i chiamanti dovrebbero eseguire sull'oggetto quando appropriato.

Sono consapevole che posso solo calcolare l'equilibrio nel suo getter. Tuttavia, non è realmente possibile perché questo è un campo entità che deve essere salvato nel database, dove ha una colonna effettiva e dove deve essere persistente l'importo calcolato.

L'altra mia preoccupazione per l'approccio di aggiornamento automatico è che i valori calcolati potrebbero essere leggermente diversi da quelli originariamente salvati nel database, a causa dei valori di arrotondamento (una versione precedente del software utilizzava i float, ma ora i decimali ). Quindi, caricando, diciamo che 2000 entità dal database potrebbero cambiare il loro stato e fare in modo che ORM ritenga che siano state modificate e che siano persistite nel database la prossima volta che il metodo SaveChanges () viene richiamato nel contesto.

Attiverà una massa di aggiornamenti a cui non sono realmente interessato, o potrebbe causare problemi, se i metodi di calcolo fossero cambiati (le entità scaricate perderebbero i loro vecchi valori per essere sostituiti da quelli appena ricalcolati, semplicemente caricando) .

Quindi, prendiamo ulteriormente l'esempio.

Ogni fattura presenta alcuni dettagli relativi alla fattura, che hanno anche BilledAmount, PaidAmount e Balance (sto semplificando il mio business case per l'esempio, quindi supponiamo che il cliente possa pagare separatamente ogni articolo della fattura piuttosto che nel suo complesso).

Se consideriamo che l'entità dovrebbe prendersi cura di se stessa, qualsiasi modifica dei dettagli del bambino dovrebbe comportare anche la modifica dei totali della fattura.

In un approccio completamente automatizzato, una semplice implementazione passerebbe in rassegna ogni dettaglio della fattura per ricalcolare i totali dell'intestazione, ogni volta che cambia la proprietà. Probabilmente andrebbe bene solo per un record, ma se un sacco di entità sono state recuperate contemporaneamente, potrebbe creare un sovraccarico significativo, poiché eseguirà questo processo ogni volta che viene recuperato un nuovo record di dettagli della fattura. Forse peggio, se i dettagli non sono già stati caricati, potrebbe far sì che l'ORM li carichi lentamente, solo per ricalcolare i saldi.

Finora, sono andato con il metodo di aggiornamento (), principalmente per le ragioni che ho spiegato sopra, ma mi chiedo se fosse giusto. Sto notando che devo continuare a chiamare questi metodi abbastanza spesso e in diversi punti del mio codice ed è una potenziale fonte di bug.

Ha anche un effetto dannoso sull'associazione dati poiché quando le proprietà del dettaglio o dell'intestazione cambiano, le altre proprietà non vengono aggiornate e il metodo non può essere chiamato.

Qual è l'approccio consigliato in questo caso?

    
posta Kharlos Dominguez 10.10.2012 - 16:26
fonte

2 risposte

1

Vedo che questo problema non è un problema di programmazione tanto quanto un problema di progettazione dello schema. Dove posizionare le proprietà e il metodo può essere secondario all'identificazione delle colonne del database se si stanno mappando le tabelle alle classi in 1-1 o vicino a 1-1.

Personalmente vedo che dopo che il tipo di dati è stato modificato, dovresti eseguire un rapporto confrontando vecchi totali e nuovi totali e vorresti probabilmente coinvolgere la gestione, quindi aggiornare il database in batch e ottenere tutti i dati coerenti una volta per tutte.

Sugli altri problemi, la risposta corretta dipenderà dal rispondere alle seguenti domande:

  1. Il tuo negozio è rigido riguardo alla normalizzazione? Se la risposta è "sì", fallo in modo normalizzato.

  2. Gli altri sistemi aggiornano le tabelle coinvolte?

  3. Hai meno di 300 figli per header? (300 è ovviamente un valore approssimativo)

  4. Circa un utente accederà alla stessa intestazione o dettaglio della stessa in qualsiasi momento

La tabella seguente riassume la mia opinione in base alle diverse risposte delle domande. Nota che (-) significa 'non importa'.

Personalmente preferisco lavorare con dati non ridondanti ogni volta che è possibile e metterei la correttezza e l'integrità dei dati rispetto alle prestazioni se dovessi farlo ed è stato da me, quindi sono di parte. Ho fatto l'ipotesi che una fattura sia normalmente accessibile solo poche volte dopo la sua creazione.

Si noti inoltre che il calcolo non deve essere fisicamente archiviato come colonna della tabella, ma potrebbe essere calcolato in una vista e tale visualizzazione viene utilizzata da qualsiasi programma che desidera accedere a tali informazioni. Assicurati che il tuo software di segnalazione possa utilizzare le viste prima di farlo.

    
risposta data 11.10.2012 - 00:05
fonte
1

È quello che chiamerei duplicazione dei dati:

Se c = a + b , allora perché è necessario memorizzare c ? a meno che il calcolo non sia costoso, ovviamente, ma non sarebbe automatico.

Mantenere questi numeri in sincrono diventa un incubo, coinvolgendo:

  • Quantità di aggiornamenti indesiderati
  • Complessazione dell'interfaccia utente che presenta
  • Db extra / carico di rete

E altro ancora.

La mia soluzione: non farlo. Ricalcola quando vuoi visualizzarla, usa i meccanismi di Binding per farlo (disponibile in WPF, SL e Javascript AFAIK).

    
risposta data 12.10.2012 - 17:36
fonte

Leggi altre domande sui tag