2013-04-03 52 views
3

負載基本I有一個問題。如果我使用LinqToSql,我的程序將加載我的數據庫到內存中。 小例子:使用LinqToSql而不在存儲器

//pageNumber = 1; pageSize = 100;     
       var result = 
        (
        from a in db.Stats.AsEnumerable() 
        where (DictionaryFilter(a, sourceDictionary) && DateFilter(a, beginTime, endTime) && ErrorFilter(a, WarnLevel)) 
        select a 
        ); 
       var size = result.Count(); // size = 1007 
       var resultList = result.Skip((pageNumber-1)*pageSize).Take(pageSize).ToList(); 
       return resultList; 

DictionaryFilter,DateFilter和ErrorFilter是我過濾DATEBASE功能。在這之後我的程序使用了〜250Mb的Ram。 如果我不使用:

var size = result.Count(); 

我的程序使用〜120MB RAM。 在使用此代碼之前,我的程序使用〜35MB Ram。

如何使用計數,並採取功能不加載我的內存中的所有DATEBASE?

static bool DateFilter(Stat table, DateTime begin, DateTime end) 
{ 

    if ((table.RecordTime >= begin.ToFileTime()) && (table.RecordTime <= end.ToFileTime())) 
    { 
     return true; 
    } 
    return false; 
} 
static bool ErrorFilter(Stat table, bool[] WarnLevel) 
{ 
    if (WarnLevel[table.WarnLevel]) return true; 
    else return false; 
} 
static bool DictionaryFilter(Stat table, Dictionary<GetSourcesNameResult, bool> sourceDictionary) 
{ 
    foreach (var word in sourceDictionary) 
    { 
     if (table.SourceName == word.Key.SourceName) 
     { 
      return word.Value; 
     } 
    } 
    // 
    return false; 
} 

回答

9

簡單:不使用.AsEnumerable()。這意味着「切換到LINQ到對象」。在此之前,db.StatsIQueryable<T>,這是一個組合的 API,並會盡你所期望的。

但是,這意味着您不能使用C#方法,如DictionaryFilterDateFilter,而必須按照Expression API編寫內容。如果你可以說明他們做什麼我可以進一步建議。

有了您編輯的過濾可以進行調整,例如:

static IQueryable<Stat> ErrorFilter(IQueryable<Stat> source, bool[] WarnLevel) { 
    // extract the enabled indices (match to values) 
    int[] levels = WarnLevel.Select((val, index) => new { val, index }) 
          .Where(pair => pair.val) 
          .Select(pair => pair.index).ToArray(); 

    switch(levels.Length) 
    { 
     case 0: 
      return source.Where(x => false); 
     case 1: 
      int level = levels[0]; 
      return source.Where(x => x.WarnLevel == level); 
     case 2: 
      int level0 = levels[0], level1 = levels[1]; 
      return source.Where(
        x => x.WarnLevel == level0 || x.WarnLevel == level1); 
     default: 
      return source.Where(x => levels.Contains(x.WarnLevel)); 
    } 
} 

日期過濾器是簡單的:

static IQueryable<Stat> DateFilter(IQueryable<Stat> source, 
     DateTime begin, DateTime end) 
{ 
    var from = begin.ToFileTime(), to = end.ToFileTime(); 
    return source.Where(table => table.RecordTime >= from 
     && table.RecordTime <= to); 
} 

和字典有點像水平:

static IQueryable<Stat> DictionaryFilter(IQueryable<Stat> source, 
    Dictionary<GetSourcesNameResult, bool> sourceDictionary) 
{ 
    var words = (from word in sourceDictionary 
       where word.Value 
       select word.Key.SourceName).ToArray(); 

    switch (words.Length) 
    { 
     case 0: 
      return source.Where(x => false); 
     case 1: 
      string word = words[0]; 
      return source.Where(x => x.SourceName == word); 
     case 2: 
      string word0 = words[0], word1 = words[1]; 
      return source.Where(
        x => x.SourceName == word0 || x.SourceName == word1); 
     default: 
      return source.Where(x => words.Contains(x.SourceName)); 
    } 
} 

和:

IQueryable<Stat> result = db.Stats; 
result = ErrorFilter(result, WarnLevel); 
result = DateFiter(result, beginTime, endTime); 
result = DictionaryFilter(result, sourceDictionary); 
// etc - note we're *composing* a filter here 

var size = result.Count(); // size = 1007 
var resultList = result.Skip((pageNumber-1)*pageSize).Take(pageSize).ToList(); 
return resultList; 

的一點是,現在我們正在使用IQueryable<T>Expression獨佔。

+0

他也許不能只是省略'AsEnumerable'。看看他的過濾器,它看起來像是由一堆定製的內存中謂詞組成的。他必須將所有過濾條款轉換爲「表達式」。編輯:確切地說。 –

+0

@WiktorZychla,如果你現在點擊「f5」... –

+0

我在我的文章中添加了過濾功能。 – EXTRAM

1

以下SO問題或許可以解釋的事情:Understanding .AsEnumerable in Linq To Sql

.AsEnumerable()加載整個表。

+0

如果我不使用AsEnumerable(),我可以使用我的c#函數嗎? – EXTRAM

+0

是的,如果你將它們編碼爲IQueryable接口。看起來像馬克的回答擊敗了我:) –

相關問題