Prestazioni relative al tipo restituito per la query LINQ compatibile con l'ordinamento automatico

StackOverflow https://stackoverflow.com/questions/1761597

Domanda

questo non è davvero un problema, ma più una preoccupazione su cui apprezzerei qualche input, per favore.

Winforms C# .net3.5[sp1] Visual Studio 2008 utilizzando Linq2Sql (più specificamente PLINQO...che tra l'altro è fantastico!).Ho un set di risultati che restituisce +/- 19000 righe di dati (con circa 80 byte di dati per riga) e ho scelto di mettere in background il metodo di recupero dei dati e aggiornare l'interfaccia utente di conseguenza.Funziona bene.

Tuttavia, ho notato alcune differenze di prestazioni quando utilizzo diversi tipi di ritorno per il mio metodo di recupero dati Ling.So che tutti suggeriscono di restituire a List<T> O IEnumarable<T>, e imposta l'origine dati di DataGridView su questo, ma sfortunatamente non supporta l'ordinamento nativo degli oggetti.Dopo aver scavato un po' in giro ho trovato il file SortableBindingList<T> SU MSDN qui.L'ho applicato e la griglia ha impiegato meno di un secondo per compilarsi, tuttavia quando faccio clic su una colonna per ordinarla, ci è voluto poco più di un secondo per implementare l'ordinamento.

Ho quindi deciso di seguire il percorso DataTable, ma ho scoperto che il metodo ToDataTable è stato rimosso, ma dopo ulteriori ricerche ho trovato un modo per implementarlo su questo Articolo MSDN.Dopo averlo applicato, ho scoperto che il recupero impiegava circa 2 secondi per popolare la griglia, ma successivamente l'ordinamento (su 19000 righe!) era istantaneo!!Naturalmente ho mantenuto questo approccio.

Tieni inoltre presente che ho disabilitato qualsiasi modifica/aggiunta/eliminazione nella griglia.La griglia serve esclusivamente per visualizzare i dati.Qualsiasi altra operazione CRUD è fornita da moduli di dialogo in base alla riga attualmente selezionata (colonna della chiave primaria nascosta).

Ecco il codice che ho usato per entrambi i metodi:

1) Elenco di associazione ordinabile

    //declare private member
    private SortableBindingList<PdtAllocation> listAlloc = null;

    private void RefreshData() {
        bcsDataContext ctx = new bcsDataContext();
        try {
            listAlloc = new SortableBindingList<PdtAllocation>(ctx.PdtAllocation.ToList());
        }
        catch (Exception) {
            throw;
        }
        finally {
            ctx.Dispose();
        }

        dataGridView1.DataSource = listAlloc;
    }

2) Copia nella tabella dati

    //declare private member
    private DataTable dt = null;

    private void RefreshData() {
        dt = new DataTable();
        bcsDataContext ctx = new bcsDataContext();
        try {
            ctx.PdtAllocation.CopyToDataTable(dt, LoadOption.PreserveChanges);
        }
        catch (Exception) {
            throw;
        }
        finally {
            ctx.Dispose();
        }

        dataGridView1.DataSource = dt;
    }

Ora so che probabilmente sembra un "chiesto e risposto" caso, ma apprezzerei molto il tuo contributo, così come eventuali problemi noti relativi all'esecuzione del progetto CopyToDataTable() itinerario.

Grazie... e ci scusiamo per la moooolta domanda!

È stato utile?

Soluzione

ecco la mia opinione sulla tua domanda (andando al SortableBindingList itinerario).

Hai utilizzato un algoritmo di ordinamento generico basato sulla riflessione?L'ho fatto all'inizio e la performance è stata davvero pessima.Alla fine ho trovato la seguente soluzione:fornire l'ordinamento predefinito SortableBindingList<T> ma lasciano anche aperta la possibilità di implementare un ordinamento specializzato nelle classi derivate.

Ecco del codice.

In SortableBindingList<T>.ApplySortCore():

protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
    // Check if the sorted property implements IComparable
    ...

    List<T> itemsList = (List<T>)this.Items;

    Comparison<T> comparer = GetComparer(prop);

    itemsList.Sort(comparer);

    if (direction == ListSortDirection.Descending)
    {
        itemsList.Reverse();
    }

    ...
    // Set sort state (is sorted, sort property, sort dir)
}

Il generico SortableBindingList<T> fornisce un selezionatore di base basato sulla riflessione:

protected virtual Comparison<T> GetComparer(PropertyDescriptor prop)
{
    return new Comparison<T>(delegate(T x, T y)
    {
        if (prop.GetValue(x) != null)
            return ((IComparable)prop.GetValue(x)).CompareTo(prop.GetValue(y));
        else if (prop.GetValue(y) != null)
            return -1 * ((IComparable)prop.GetValue(y)).CompareTo(prop.GetValue(x));
        else
            return 0;
    });
}

Come potete vedere, GetComparer() è virtuale, quindi è possibile sovrascriverlo in una classe derivata da SortableBindingList<T> al fine di fornire a tanto comparatore più veloce, adattato al tipo di proprietà effettivamente ordinata.Ad esempio, mentre l'operatore di confronto generico ordinato (per a String property) 10000 record in 4 secondi, il comparatore specializzato ha fatto lo stesso lavoro in 70ms.

class CustomerList : SortableBindingList<Customer>
{
    protected override Comparison<Customer> GetComparer(PropertyDescriptor prop)
    {
        Comparison<Customer> comparer = null;
        switch (prop.Name)
        {
            case "FirstName":
                comparer = new Comparison<Customer>(delegate(Customer x, Customer y)
                {
                    string xx = (null == x) ? null : x.FirstName;
                    string yy = (null == y) ? null : y.FirstName;
                    return String.Compare(xx, yy);
                });
                break;
            ...
        }
        return comparer;
    }
}

Una nota finale:gran parte del codice pubblicato è stato copiato/ispirato da altre fonti, come SO o Microsoft, quindi il merito non è mio.Il mio unico contributo è stato la virtualizzazione del comparatore, ma sono sicuro che un po' di ricerca su Google farebbe emergere soluzioni migliori e precedenti basate sulla stessa idea.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top