2009-11-19 38 views
0

這不是一個真正的問題,但更多的關注,我會感謝一些請輸入。關於LINQ查詢返回類型的性能兼容自動排序

Winforms C#.net3.5 [sp1] Visual Studio 2008使用Linq2Sql(更具體地說PLINQO ...這是一個夢幻般的順便說一句!)。我有一個結果集返回+/- 19000行數據(每行約80bytes數據),並選擇將數據檢索方法推送到後臺並相應地更新UI。這工作正常。

但是,我注意到我的Ling數據檢索方法使用不同的返回類型時有一些性能差異。我知道每個人都建議返回一個List<T>IEnumarable<T>,並將DataGridView的數據源設置爲該數據源,但不幸的是,它不支持本地排序對象。經過一番挖掘,我發現MSDN here上的SortableBindingList<T>。我應用了它,網格花了不到一秒鐘時間來填充 - 但是當我點擊一列來對它進行排序時,花了一秒鐘左右的時間來實現排序。

然後我決定去DataTable路由,但發現ToDataTable方法已被刪除,但經過更多的挖掘後發現了一個方法來實現它在這個MSDN article。應用之後,我發現檢索花了大約2秒來填充網格,但之後排序(在19000行!)瞬間!當然,我堅持這種做法。

另外請記住,我已禁用任何網格內編輯/添加/刪除。網格純粹是爲了顯示數據。根據當前所選行(隱藏主鍵列),對話框表單提供任何其他CRUD操作。

下面是我用這兩種方法的代碼:

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

現在我知道這可能看起來像一個「問及答案」的情況下,但我真的很感謝你的意見,以及與CopyToDataTable()路線有關的任何已知問題。

謝謝你......併爲looong查詢道歉!

回答

1

這是我對你的問題(去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>爲了提供一個很多更快的比較器,調整到實際排序的屬性的類型。例如,當通用比較器在4秒內排序(通過String屬性)10000條記錄時,專用比較器在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; 
    } 
} 

最後請注意:很多代碼的發佈被複制/來自其他來源,像這樣或微軟的啓發,所以信用是不是我的。我唯一的貢獻是對比較器進行虛擬化,但我相信一點Google會更好,早期的解決方案基於相同的想法。

+0

嘿索林! 「*您是否使用通用的基於反射的排序算法?*」不,只是按原樣使用......沒有改變任何事物。你提供的代碼非常棒!但任何我不應該使用DataTable的原因? – Shalan 2009-11-19 16:44:10

+0

那麼,我的第一反應是「爲什麼要複製到DataTable中,以便手頭可以對收藏進行分類?」。我不知道。也許複製到一個DataTable可以給我一些其他方便的選項,我現在看不到。期待看到別人對此有何評論。 – 2009-11-19 17:01:55

+0

自己的「ctx.PdtAllocation」返回System.Data.Linq.Table 。此後,「轉換」爲其他類型的選擇依然存在。我的理解是,對「.CopyToDataTable()」採取的工作量與「.ToList()」相同......所以我最終選擇了更好的表面(表面上)。對此有何進一步想法? – Shalan 2009-11-19 20:45:13