Chiama una funzione su ogni record dal risultato dapper

asp.net-mvc-5 c# dapper

Domanda

Sto provando a chiamare una funzione su ogni record che imposterà alcuni valori di campo. Quando i risultati devono essere cercati, questo si ottiene nel seguente modo:

public IDataWrapper GetPagedQuery<T>(string myQuery, object param, Action<T> customAction)
{
    var obj = new DataWrapper ();
    using (var oConn = CreateConnection(ConnectionString))
    {
        TotalPages totalRows = null;
        var list = oConn.Query<T, TotalPages, T>(myQuery, (e, t) =>
        {
            totalRows = t;
            if (mapAction != null) customAction(e);
            return e;
        }, param, splitOn: "SplitOn");
        obj.RowsFound = (IEnumerable<dynamic>)list;
        obj.TotalRows = totalRows == null ? 0 : totalRows.TotalRows;
    }
    return obj;
}

Il mio problema arriva quando i risultati non devono essere cercati. La mia query nel primo esempio include split on column e questo è il motivo per cui tutto funziona, tuttavia la mia prossima query è una semplice query, come Select Column1, Column2 FROM MyAwesomeTable che restituirà tutte le righe, colonne ecc ...

Il problema è che ho ancora bisogno di applicare CustomAction su ogni risultato che ritorna. Ora immaginiamo, che ci sia un potenziale di qualche milione di dischi che tornano indietro (credetemi, non è irrealistico data la mia situazione), in quanto tale non voglio più riascoltare ogni record e applicare il mio metodo, voglio quel metodo applicato come il dapper restituisce risultati, proprio come nel primo caso.

Ecco cosa ho provato:

public IDataWrapper GetNonPagedQuery<T>(string myQuery, object param, Action<T> customAction)
{
    var obj = new DataWrapper ();
    using (var oConn = CreateConnection(ConnectionString))
    {
        var list = oConn.Query<T>(myQuery, (e) =>
        {
            if (mapAction != null) customAction(e);
            return e;
        }, param).ToList();
        obj.RowsFound = (IEnumerable<dynamic>)list;
        obj.TotalRows = list.Count();
    }
    return obj;
}

Ottengo un errore per il codice precedente che non può risolvere il metodo Query<T>(etc... Capisco perché non esiste. Sto qui chiedendo quale sarebbe il modo migliore per realizzare ciò che sto cercando di fare ? È possibile con azzimato.

Risposta accettata

Ho paura che la risposta breve sia che non puoi farlo.

La risposta leggermente più lungo è che nella query di paging, che è essenzialmente un secondo passaggio attraverso i dati dal Dapper fa qualche lavoro per tradurre i dati di ciascuna riga in un'istanza di "T" e quindi si effettua una chiamata separata al metodo "mappa" che usi per chiamare la tua "CustomAction".

Quindi, ci sarebbe una minima differenza tra questo e una semplice chiamata "conn.Query" non di paging seguita da un passaggio successivo per eseguire la tua CustomAction. Qualcosa come il seguente:

public IDataWrapper GetNonPagedQuery<T>(string myQuery, object param, Action<T> customAction)
{
    var obj = new DataWrapper();
    using (var oConn = CreateConnection(ConnectionString))
    {
        var results = oConn
            .Query<T>(myQuery)
            .ToList();
        obj.TotalRows = results.Count();
        obj.RowsFound = results
            .Select(value =>
            {
                customAction(value);
                return value;
            })
            .Cast<dynamic>();
    }
    return obj;
}

Se la tua preoccupazione è che potresti caricare molti, molti record nella query non di paging, allora vale la pena ricordare che tutti quei record saranno caricati nella memoria in una sola volta; non saranno estratti dal database uno alla volta come il tuo elenco sopra i risultati restituiti e questo potrebbe essere un notevole drenaggio delle risorse (se stai parlando di così tanti dati che vuoi evitare una seconda enumerazione) .

Questo deve essere il caso in quanto la connessione SQL viene chiusa quando viene restituito GetNonPagedQuery e quindi non è possibile lasciarlo aperto per leggere i dati "su richiesta" dal chiamante. Se stai davvero lavorando con enormi quantità di dati, forse una query non di pagina non è l'approccio migliore?

Si noti che nel codice precedente, "CustomAction" verrà chiamato solo quando si enumera le righe, quelle non verranno attivate prima che restituisca GetNonPagedQuery. Se "customAction" è potenzialmente un'operazione costosa, ciò potrebbe essere vantaggioso per te. D'altra parte, se si desidera richiamare "customAction" per ogni risultato prima che restituisca GetNonPagedQuery, sarà necessaria una ulteriore chiamata ToList () dopo Cast <dynamic> (), dipende solo da quale scenario è più utile.


Risposta popolare

Sì, forse è:

Vedi la sezione dei documenti di Dapper su Cambio di tipo per riga . Dubito (cioè non l'ho provato io stesso) che non avrebbe funzionato se si fosse utilizzato lo stesso sistema per massaggiare i risultati nel formato desiderato leggendo ogni riga e elaborandola esplicitamente.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché