Производительность в отношении типа возвращаемого значения для запроса LINQ, совместимого с автоматической сортировкой

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

Вопрос

На самом деле это не проблема, а скорее беспокойство, и я был бы признателен за ваше мнение, пожалуйста.

Winforms C# .net3.5[sp1] Visual Studio 2008 с использованием Linq2Sql (точнее ПЛИНКО...что, кстати, потрясающе!).У меня есть набор результатов, возвращающий +/- 19 000 строк данных (около 80 байт данных на строку), и я решил перенести метод получения данных на задний план и соответствующим образом обновить пользовательский интерфейс.Это работает нормально.

Однако я заметил некоторые различия в производительности при использовании разных типов возвращаемых данных для моего метода получения данных Ling.Я знаю, что все предлагают вернуть List<T> или IEnumarable<T>, и установите для него источник данных DataGridView, но, к сожалению, он не поддерживает собственную сортировку объектов.Немного покопавшись, я нашел SortableBindingList<T> на MSDN здесь.Я применил его, и сетка заполнилась менее чем за секунду, однако, когда я нажимаю на столбец, чтобы отсортировать его, реализация сортировки заняла чуть больше секунды или около того.

Затем я решил пойти по маршруту DataTable, но обнаружил, что метод ToDataTable был удален, но после дальнейшего копания нашел способ реализовать его в этом случае. Статья MSDN.Применив его, я обнаружил, что заполнение сетки занимает около 2 секунд, но после этого сортировка (по 19 000 строк!) происходит мгновенно!Естественно, я придерживался этого подхода.

Также имейте в виду, что я отключил любое редактирование/добавление/удаление в сетке.Сетка предназначена исключительно для отображения данных.Любые другие операции CRUD предоставляются диалоговыми формами в соответствии с текущей выбранной строкой (столбец скрытого первичного ключа).

Вот код, который я использовал для обоих методов:

1) Сортируемый список привязок

    //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) Копироватьтаблицу данных

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

Теперь я знаю, что это, вероятно, похоже на "вопрос-и-ответ", но я был бы очень признателен за ваш вклад, а также за любые известные проблемы, связанные с выполнением CopyToDataTable() маршрут.

Спасибо....и извините за долгий вопрос!

Это было полезно?

Решение

вот мой взгляд на ваш вопрос (собираясь SortableBindingList маршрут).

Использовали ли вы общий алгоритм сортировки на основе отражения?Сначала я сделал это, и производительность была очень плохой.Наконец я придумал следующее решение:обеспечить сортировку по умолчанию SortableBindingList<T> но также оставить открытой возможность реализации специализированной сортировки в производных классах.

Вот некоторый код.

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

Общий SortableBindingList<T> предоставляет базовый сортировщик на основе отражений:

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

Как вы видете, GetComparer() является виртуальным, поэтому его можно переопределить в классе, производном от SortableBindingList<T> для того, чтобы обеспечить много более быстрый компаратор, настроенный на тип фактически сортируемого свойства.Например, в то время как общий компаратор сортирует (по String свойство) 10000 записей за 4 секунды, специализированный компаратор выполнил ту же работу за 70мс.

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

Последнее замечание:большая часть опубликованного кода была скопирована/вдохновлена ​​из других источников, таких как SO или Microsoft, поэтому это не моя заслуга.Моим единственным вкладом была виртуализация компаратора, но я уверен, что небольшой поиск в Google поможет найти более ранние решения, основанные на той же идее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top