Design pattern per la registrazione delle modifiche negli oggetti padre / figlio salvati nel database

5

Ho due tabelle di database nella relazione genitore / figlio come una tantum.

Ho tre classi che rappresentano i dati in queste due tabelle:

Parent Class
{
    Public int ID {get; set;}
    .. other properties
}

Child Class
{
    Public int ID {get;set;}
    Public int ParentID {get; set;}
    .. other properties
}

TogetherClass
{
    Public Parent Parent;
    Public List<Child> ChildList;
}

Infine ho un'applicazione client e server - ho il controllo di entrambe le estremità, quindi posso apportare modifiche a entrambi i programmi come è necessario.

Il cliente effettua una richiesta per ParentID e riceve una classe Together per il genitore corrispondente e tutti i record figli.

L'app client può apportare modifiche ai bambini - aggiungere nuovi bambini, rimuovere o modificare quelli esistenti. L'app client invia quindi la classe Together all'app server.

L'app del server deve aggiornare i record padre e figlio nel database.

Inoltre vorrei poter registrare le modifiche - lo sto facendo avendo due tabelle separate una per Parent, una per bambino; ciascuna contenente le stesse colonne dell'originale data di modifica aggiunta, da chi e un elenco delle modifiche.

Non sono sicuro dell'approccio migliore per rilevare le modifiche nei record: nuovi record, record da eliminare, record senza campi modificati, record con alcuni campi modificati.

Penso di aver bisogno di leggere il genitore & i bambini registrano e li confrontano con quelli della classe insieme.

Strategia A:

Se il record figlio della classe Together ha un ID di dire 0, questo indica un nuovo record; inserire. Tutti i record figli eliminati non sono più nella Classe Insieme; verificare se nessuno dei record figlio di confronto non è stato trovato nella classe Together e delete if not found (Compare using ID).

Controlla ogni record figlio per le modifiche e se ha cambiato registro.

Strategia B: Crea una nuova TogetherClass aggiornata

UpdatedClass
{
    Public Parent Parent {get; set}
    Public List<Child> ListNewChild {get;set;}
    Public List<Child> DeletedChild {get;set;}
    Public List<Child> ExistingChild {get;set;} // used for no changes and modified rows
}

E poi elaborare secondo l'elenco.

Il motivo per cui sto chiedendo idee è che entrambe queste soluzioni non mi sembrano ottimali e sospetto che questo problema sia già stato risolto - una sorta di modello di progettazione?

Sono consapevole di un potenziale problema in questo approccio generale - quello in cui l'App Client A richiede un record; L'app B richiede lo stesso record; A salva quindi i cambiamenti; B salva quindi le modifiche che potrebbero sovrascrivere le modifiche A apportate. Questo è un problema di blocco separato che solleverò una domanda a parte se ho problemi nell'implementazione.

L'implementazione effettiva è c #, SQL Server e WCF tra client e server - condivisione di una libreria contenente le implementazioni di classe.

Scusa se questo è un post duplicato - ho provato a cercare vari termini senza trovare una corrispondenza però.

Aggiornamento basato sui commenti di svick e TimG:

Per tenere traccia delle modifiche, la classe base dovrebbe essere qualcosa come:

public class ChangedRowBase
    {
        public enum StatusState
        {
        New, Unchanged, Updated, Deleted
    };

    protected StatusState _Status;

    public StatusState Status
    {
        get
        {
            return _Status;
        }
    }

    public void SetUnchanged()
    {
        _Status = StatusState.Unchanged;
    }

    public void SetDeleted()
    {
        _Status = StatusState.Deleted;
    }

}

Quindi la classe di mio figlio avrebbe qualcosa del tipo:

    public int SomeDumbProperty
    {
        get;
        set
        {
            base.Status = StatusState.Updated;
            // Missing line here to set the property itself
        }
    }

    private int _SomeIntelligentProperty;

    public int SomeIntelligentProperty
    {
        get { return _SomeIntelligentProperty; }

        set
        {
            if (value != _SomeIntelligentProperty)
            {
                _SomeIntelligentProperty = value;
                base.Status = StatusState.Updated;
            }
        }
    }

L'idea è che l'intelligente rilevi se c'è stato davvero un cambiamento; in caso contrario, con l'uso di quello stupido l'app client dovrà rilevare la modifica e aggiornarla solo se è stata apportata una modifica oppure utilizzare comunque il setter che segnala una modifica che in realtà non si verificava.

So anche che la mia proprietà non funziona (o non compila) in questo momento. Se voglio il codice nel getter o setter, significa che devo definire una variabile privata separata io stesso? Conosco la mano corta {get; set;} fa questo dietro le quinte.

    
posta andrew 25.06.2013 - 15:53
fonte

2 risposte

1

Qui ci sono schemi di progettazione comuni per gestire questi scenari.

Imposta una classe base. Il bambino e il genitore erediteranno dalla base. La classe base dovrebbe fare quanto segue:

  1. Avere una proprietà .Status (sola lettura) che tiene traccia se un oggetto è {invariato, nuovo, aggiornato, cancellato} Lo stato è impostato durante il metodo {costruttore, .delete (), ogni setter della proprietà}. Avrai bisogno di un metodo factory per generare un'istanza dell'oggetto con uno stato di "immutato" o un metodo per contrassegnare se stesso come "invariato".
    btw. Questo approccio rende un oggetto più "atomico" perché è autonomo e tiene traccia dei propri cambiamenti. Questo è anche un esempio del perché le persone usano Proprietà (getter / setter) invece di vars pubbliche.

  2. Un meccanismo di pseudo blocco comunemente utilizzato consiste nell'utilizzare una combinazione di colonne .LastModifiedDateTime (sola lettura) e .LastModifier (sola lettura) su ogni tabella DB (non tabella di codice / tabella statica). Questi sono anche impostati nel metodo costruttore / fabbrica. In Aggiornamento / Salva, confronta l'attuale LastModifiedDateTime & LastModifier al DB. Se non corrispondono, rifiuta questa modifica.

# 1 è simile al modo in cui molti ORM mantengono lo stato (modifica dell'handle). Il # 2 è spesso indicato come un "meccanismo di blocco morbido".

    
risposta data 25.06.2013 - 20:25
fonte
0

Penso che una buona soluzione qui sarebbe che il modello client rilevi le modifiche a se stesso e quindi invii al server solo le modifiche.

Ciò significa che i setter delle tue proprietà dovranno almeno registrare che qualcosa è cambiato. E le collezioni non possono essere semplici List<T> s, ma qualcosa che può avere una reazione personalizzata alle modifiche. (Puoi usare Collection<T> con metodi sovrascritti come InsertItem() per questo.)

    
risposta data 25.06.2013 - 16:42
fonte

Leggi altre domande sui tag