La memorizzazione nella cache appartiene a una classe di repository?

2

Sono andato avanti e indietro su questo problema diverse volte.

Da un lato, si potrebbe obiettare, la responsabilità unica di un repository è quella di gestire lo stato persistente di un'entità, e l'applicazione consumante è quella che sa se accetterà un valore scaduto o non in cambio di prestazioni.

Tuttavia, se si ha a che fare con una cache fuori processo e molte applicazioni / server hanno tutti bisogno dello stesso valore memorizzato nella cache, mettere il codice di memorizzazione nella cache nel repository è un posto conveniente e contribuirebbe ad evitare la duplicazione della cache. Dato che a quel punto c'è una singola cache che agisce come una singola fonte di verità e che funge da buffer per il DB, sembra più appropriato che un repository contenga il codice di memorizzazione nella cache.

Il codice di memorizzazione nella cache appartiene a un repository?

Che cosa significa specificamente una cache fuori processo (come redis) che funge da buffer per il database?

Se il codice di cache non appartiene a un repository, dove dovrebbe risiedere se molti pezzi di codice disperati hanno bisogno dello stesso valore?

    
posta TheCatWhisperer 09.08.2017 - 20:14
fonte

3 risposte

4

È possibile utilizzare un design adeguato per ottenere il meglio da entrambi i mondi. Potresti usare il modello decoratore come suggerito da Vincent.

In questo modello hai CachingRepository che implementa l'interfaccia del tuo repository e ha un'istanza del repository a cui delega le chiamate (quando c'è un errore di cache). Questo design separa le preoccupazioni di cache e le entità di recupero, ma invisibilmente al client di Repository .

Lo psuedocode di CachingRepository sarebbe:

getFoo(id): Foo
  if cache contains id
    return cached Foo
  else
    call getFoo on delegate
    store result of getFoo in cache
    return result

Nella tua radice composizione creerai un'istanza di CachingRepository con DbRepository come suo delegato

Repository repo = new CachingRepository(new DbRepository(...));
    
risposta data 09.08.2017 - 21:54
fonte
1

Penso che in genere dipenda dalla natura dei dati memorizzati nella cache e dallo scopo. Alcune cache dovrebbero trovarsi nel repository. Queste sono le cache progettate per fornire accesso accelerato a valori coerenti e accurati. Esempi di basso livello sarebbero cache del disco, piani di query DB, anche valori da una cache Redis che sono pensati per essere un rapido riflesso dei valori attuali, attuali.

Le cache delle applicazioni sono bestie diverse e non devono vivere nel repository attuale o essere condivise. Un esempio potrebbe essere un elenco di codici ticker conservati nel server Web (o persino nella memoria locale del browser) validi per un giorno.

I prezzi dei ticker in tempo reale possono essere da qualche parte nel mezzo - persistenti in un repository "corretto" ma allo stesso tempo resi disponibili alle applicazioni in un modo più veloce, se meno flessibile o coerente (di nuovo, come una copia in Redis o simile).

Penso che il riassunto sia che hai bisogno di tecniche diverse per circostanze diverse, da qui la tua schiena & avanti cercando di arrivare all '"unica vera risposta" che non c'è.

    
risposta data 10.08.2017 - 02:54
fonte
0

Si può separare in modo che il database o il "repository" non abbiano idea che i dati vengano memorizzati nella cache. Questa è una soluzione pulita e può essere implementata secondo necessità attraverso i metodi di query del repository. Come @Vincent suggerisce che questo è un tipo di decoratore di pattern. Finga IQuery è il comando repository per ottenere i dati (TOut). (TIn) può essere una sorta di oggetto che rappresenta un criterio o parametri utilizzati dal comando query.

Se i dati non sono nella cache, usiamo il repository per recuperarlo.

public class QueryCaching<TIn, TOut> : IQuery<TIn, TOut>
    {
        private readonly ICache _cache;
        private readonly IQuery<TIn, TOut> _command;
        private readonly string _key;

        public QueryCaching(string key, ICache cache, IQuery<TIn, TOut> command)
        {
            _command = command;
            _key = key;
            _cache = cache;
        }

        public TOut Execute(TIn input)
        {
            TOut obj;
            if (_cache.Get(_key, out obj))
            {
                Debug.WriteLine(string.Format("Cache hit for key {0}", _key));
                return obj;
            }

            Debug.WriteLine(string.Format("Cache miss for key {0}", _key));
            obj = _command.Execute(input);
            _cache.Set(_key, obj);

            return obj;
        }
    }
    
risposta data 09.08.2017 - 21:47
fonte

Leggi altre domande sui tag