Desempenho em relação ao tipo de retorno para consulta LINQ Compatível com classificação automática

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

Pergunta

Isso não é realmente um problema, mas mais uma preocupação que eu apreciaria algumas informações, por favor.

WinForms C# .NET3.5 [SP1] Visual Studio 2008 usando LINQ2SQL (mais especificamente Plinqo... que é fantástico BTW!). Eu tenho um ResultSet retornando +/- 19000 linhas de dados (com cerca de 80 bytes de dados por linha) e optei por empurrar o método de recuperação de dados para o plano de fundo e atualizar a interface do usuário de acordo. Isso funciona bem.

No entanto, notei algumas diferenças de desempenho ao usar diferentes tipos de retorno para o meu método de recuperação de dados Ling. Eu sei que todo mundo sugere devolver um List<T> ou IEnumarable<T>, e defina o DataGridView DataSource para isso, mas infelizmente ele não suporta a classificação nativamente para objetos. Depois de alguns cavando, encontrei o SortableBindingList<T> sobre Msdn aqui. Eu o apliquei, e a grade levou menos de um segundo para se preencher - no entanto, quando clico em uma coluna para classificá -la, demorou um pouco mais de um segundo para implementar o tipo.

Decidi então seguir a rota do Datatable, mas descobri que o método Todatatable foi removido, mas depois de mais escavação encontrou uma maneira de implementá -lo sobre isso Artigo do MSDN. Depois de aplicá -lo, descobri que a recuperação levou cerca de 2 segundos para preencher a grade, mas depois a classificação (em 19000 linhas!) Foi instantânea !! Naturalmente, fiquei com essa abordagem.

Lembre-se também de que desativei qualquer edição/adição/exclusão da grade. A grade é puramente para exibir dados. Quaisquer outras operações do CRUD são fornecidas pelos formulários de diálogo de acordo com a linha atual selecionada (coluna de chave primária oculta).

Aqui está o código que usei para os dois métodos:

1) SortableBindingList

    //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) CopyTodatatable

    //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;
    }

Agora eu sei que isso provavelmente parece ser um "perguntado e respondeu"Caso, mas eu realmente apreciaria sua contribuição, bem como quaisquer problemas conhecidos em ir para o CopyToDataTable() rota.

Obrigado .... e desculpas pela consulta Looong!

Foi útil?

Solução

Aqui está minha opinião sobre sua pergunta (indo para o SortableBindingList rota).

Você usou um algoritmo genérico baseado em reflexão? Eu fiz isso no começo e a performance foi muito ruim. Finalmente, criei a seguinte solução: Forneça a classificação padrão em SortableBindingList<T> mas também deixe em aberto a possibilidade de implementar classificação especializada em classes derivadas.

Aqui está algum código.

Dentro 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)
}

O genérico SortableBindingList<T> Fornece um classificador básico baseado em reflexão:

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;
    });
}

Como você pode ver, GetComparer() é virtual, para que se possa substituí -lo em uma classe derivada de SortableBindingList<T> Para fornecer um Muito de Comparador mais rápido, ajustado para o tipo de propriedade que está sendo classificada. Por exemplo, enquanto o comparador genérico classificou (por um String Propriedade) 10000 Registros em 4 segundos, a comparadora especializada fez o mesmo trabalho em 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;
    }
}

Uma nota final: grande parte do código publicado foi copiado/inspirado de outras fontes, como So ou Microsoft, para que o crédito não seja meu. Minha única contribuição foi virtualizar o comparador, mas tenho certeza de que um pouco de Google surgiria melhor, soluções anteriores com base na mesma idéia.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top