2010-11-02 34 views
3

我正在爲分頁添加HtmlHelper,但我不確定從性能和可維護性的角度來看,哪裏放置了分頁代碼的某些部分的適當和/或最有用的地方。ASP.NET MVC2 LINQ - 存儲庫模式,分頁代碼應該放在哪裏?

我不確定Linq到SQL數據操作的Skip(),Take()和Count()部分是否應該存儲在存儲庫或控制器中。

我也不確定他們的訂單和使用地點是否會以任何方式影響績效。

如果他們住的地方離我的理解倉庫內,這是它如何工作:
我會通過的PageIndex和pageSize的作爲參數從數據庫中抓取數據存儲庫的方法。
2.然後從數據庫中抓取完整的數據集。
3.然後將該完整數據集的TotalItems的計數存儲在一個變量中。
4.然後應用Skip()和Take(),這樣數據集只保留我需要的頁面。
5.將部分數據集顯示爲視圖中的單個頁面。

如果他們住在控制器上,我的理解是這是如何工作的: 1.我會從存儲庫中抓取完整的數據集並將其存儲到控制器內的變量中。 2.然後獲取完整數據集的TotalItems的數量。 3.然後應用Skip()和Take(),這樣數據集只保留我需要的頁面。 4.在視圖中將部分數據集顯示爲單個頁面。

控制器內(我知道我會不正確地獲取頁面這裏並不算TOTALITEMS):


Character[] charactersToShow = charactersRepository.GetCharactersByRank(this.PageIndex, this.PageSize); 
RankViewModel viewModel = new RankViewModel 
{ 
    Characters = charactersToShow, 
    PaginationInfo = new PaginationInfo 
    { 
     CurrentPage = this.PageIndex, 
     ItemsPerPage = this.PageSize, 
     TotalItems = charactersToShow.Count() 
    } 
}; 

在倉庫裏:


public Character[] GetCharactersByRank(int PageIndex, int PageSize) 
{ 
    IQueryable characters = (from c in db.Characters 
     orderby c.Kill descending 
     select new Character { 
      CharID = c.CharID, 
      CharName = c.CharName, 
      Level = c.Level 
     }); 
    characters = PageIndex > 1 ? characters.Skip((PageIndex - 1) * PageSize).Take(PageSize) : characters.Take(PageSize); 
    return characters.ToArray(); 
} 

這段代碼是如何我的部分示例正在實施存儲庫中的Skip(),Take()和Count()代碼。我沒有真正實現獲取和返回TotalItems,因爲那時我意識到我不知道放置這個的適當位置。

部分原因我不確定把這些放在哪裏是我不知道Linq to SQL如何在底層工作,因此我不知道如何優化性能。在這種情況下,我也不知道這是否是一個問題。

當您在Linq to SQL上執行.Count()時,是否必須從數據庫中獲取所有記錄? 如果我做了一個.Count(),那麼它是否需要做單獨的查詢?然後再做一個.Skip()和.Take()? 在.Skip()和.Take()之前使用.Count()有沒有可能的性能問題?

這是我第一次使用ORM,所以我不確定會發生什麼。我知道我可以查看Linq to SQL的查詢,但是我覺得在這種情況下傾聽有經驗的人會更好地利用我的時間。

我想更深入地瞭解這一點,任何見解將不勝感激。

+0

回答*一個*你的問題,是的 - 它需要做2個數據庫調用。唯一避免這種情況的方法是在數據庫本身中進行100%的分頁。 – RPM1984 2010-11-02 07:28:03

回答

2

我發現這對馬爾科上述的NerdDinner網站,它回答了很多我的問題。

的NerdDinner第8頁的底部:

IQueryable的是一個非常強大的功能,使各種有趣的延遲執行的情況(如尋呼和組成基於查詢)。與所有強大的功能一樣,您要小心使用它,並確保它不被濫用。
重要的是要認識到從存儲庫返回一個IQueryable結果可以調用代碼在鏈式運算符方法上附加它,並參與最終的查詢執行。如果你不想提供調用代碼這個能力,那麼你應該返回IList或IEnumerable結果 - 它包含已經執行的查詢的結果。
對於分頁場景,這需要您將實際的數據分頁邏輯推送到所調用的存儲庫方法中。在這種情況下,我們可能會更新我們的FindUpcomingDinners()finder方法有一個簽名,要麼返回PaginatedList:
PaginatedList <晚餐> FindUpcomingDinners(INT的PageIndex,詮釋的pageSize){}
還是回到回一個IList,並使用 「TOTALCOUNT」 出PARAM返回晚宴的總數:
IList的FindUpcomingDinners(INT的PageIndex,詮釋的pageSize,OUT INT TOTALCOUNT){}

2

我在我的Helpers文件夾中保留了一個通用的PaginatedList類,我也放了其他的Helper類。

PaginatedList是直接從NerdDinner,它看起來像這樣。

public class PaginatedList<T>: List<T> 
{ 
    public int PageIndex { get; private set; } 
    public int PageSize { get; private set; } 
    public int TotalCount { get; private set; } 
    public int TotalPages { get; private set; } 

    public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize) 
    { 
     PageIndex = pageIndex; 
     PageSize = pageSize; 
     TotalCount = source.Count(); 
     TotalPages = (int) Math.Ceiling(TotalCount/(double)PageSize); 

     this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize)); 
    } 

    public bool HasPreviousPage 
    { 
     get 
     { 
      return (PageIndex > 0); 
     } 
    } 

    public bool HasNextPage 
    { 
     get 
     { 
      return (PageIndex + 1 < TotalPages); 
     } 
    } 
} 
+0

這個問題是每次觸發2個查詢 - 一個用於'.Count()',另一個用於Skip/Take組合。但是我還沒有找到一種方法來避免這種情況。只有其他選項是做分頁數據庫端。 – RPM1984 2010-11-02 07:27:05

+0

我在NerdDinner網站上找到了我正在尋找的東西,感謝您的參考:) – Sgraffite 2010-11-03 04:37:50