2013-07-28 50 views
0

這裏是我的代碼快照正常工作:Linq查詢無法轉換爲SQL:如何優化代碼?

var q1 = from msg in db.GetTable<Message>() 
       .Where(msg0 => ...) 
     from mt in db.GetTable<MessageTo>() 
       .Where(mt0 => ...)          
       .DefaultIfEmpty() 
     select new { msg, mt } 
        ; 

AgeTypeEnum eAgeType = (AgeTypeEnum)age.Value; 
switch (eAgeType) 
{ 
case AgeTypeEnum.Invalid: 
    break; 

case AgeTypeEnum.LastWeek: 
    q1 = q1.Where(q => q.msg.CreatedDate >= DateTime.Now.AddDays(-7)); 
    break; 

case AgeTypeEnum.LastMonth: 
    q1 = q1.Where(q => q.msg.CreatedDate >= DateTime.Now.AddMonths(-1) && q.msg.CreatedDate < DateTime.Now.AddDays(-7)); 
    break; 

case AgeTypeEnum.CurrentSeason: 
    q1 = q1.Where(q => q.msg.CreatedDate >= Season.CurrentSeason.FirstPlayedDay.RealDate && q.msg.CreatedDate < DateTime.Now.AddDays(-7)); 
    break; 

case AgeTypeEnum.LastSeason: 
    q1 = q1.Where(q => q.msg.CreatedDate >= Season.PreviousSeason.FirstPlayedDay.RealDate && q.msg.CreatedDate < Season.CurrentSeason.FirstPlayedDay.RealDate); 
    break; 

case AgeTypeEnum.PreviousSeasons: 
    q1 = q1.Where(q => q.msg.CreatedDate < Season.PreviousSeason.FirstPlayedDay.RealDate); 
    break; 

default: 
    throw new MyException("'{0}' age type is not supported", eAgeType); 
} 
return q1.Select(q => new {MessageObj = q.msg}).ToList(); 

此代碼工作正常,但它是相當位。幷包含潛在的可重用邏輯。我想優化它以下列方式:

Func<Message, bool> qAgeFilter; 
AgeTypeEnum eAgeType = (AgeTypeEnum)age.Value; 
switch (eAgeType) 
{ 
case AgeTypeEnum.Invalid: 
    qAgeFilter = null; 
    break; 

case AgeTypeEnum.LastWeek: 
    qAgeFilter = msg => msg.CreatedDate >= DateTime.Now.AddDays(-7); 
    break; 

case AgeTypeEnum.LastMonth: 
    qAgeFilter = msg => msg.CreatedDate >= DateTime.Now.AddMonths(-1) && msg.CreatedDate < DateTime.Now.AddDays(-7); 
    break; 

case AgeTypeEnum.CurrentSeason: 
    qAgeFilter = msg => msg.CreatedDate >= Season.CurrentSeason.FirstPlayedDay.RealDate && msg.CreatedDate < DateTime.Now.AddDays(-7); 
    break; 

case AgeTypeEnum.LastSeason: 
    qAgeFilter = msg => msg.CreatedDate >= Season.PreviousSeason.FirstPlayedDay.RealDate && msg.CreatedDate < Season.CurrentSeason.FirstPlayedDay.RealDate; 
    break; 

case AgeTypeEnum.PreviousSeasons: 
    qAgeFilter = msg => msg.CreatedDate < Season.PreviousSeason.FirstPlayedDay.RealDate; 
    break; 

default: 
    throw new MyException("'{0}' age type is not supported", eAgeType); 
} 
if (qAgeFilter != null) 
{ 
    q1 = q1.Where(q => qAgeFilter(q.msg)); 
} 

事實上,不同的是,而不是修改Q1對象(查詢本身),我結合新的委託和查詢表達式中使用它之後。

當試圖執行優化的代碼我收到異常:

「調用(值(vfm_elita.ServiceLayer.DataLogicLayer.Messages.MessagesExtension + <> C_ DisplayClass21 + <>Ç _DisplayClass2c).qAgeFilter, q.msg)'無法轉換爲SQL。

問題:

  1. 有什麼錯我的代碼?

  2. 你會如何建議,以便提取可重複使用的邏輯組成「過濾器」授人以優化的源代碼?

謝謝

附:我使用ASP.NET 4.0,MySQL 5.0,BLToolKit作爲數據庫訪問引擎。

回答

1

爲2點,你可以使用一個擴展方法,

public Table<Message>  Messages    { get { return GetTable<Message>(); } } 

from msg in db.Messages.ForAge(age) 
         .Where(msg0 => ...) 



private static IQueryable<Message> ForAge(this IQueryable<Message> messages, AgeTypeEnum ageType) 
{ 
    switch(ageType)  
    { 
     case AgeTypeEnum.Invalid: return messages; 
     case AgeTypeEnum.LastWeek: return messages.Where(q => q.msg.CreatedDate >= DateTime.Now.AddDays(-7)); 
     case AgeTypeEnum.LastMonth: return messages.Where(q => q.msg.CreatedDate >= DateTime.Now.AddMonths(-1) && 
                  q.msg.CreatedDate < DateTime.Now.AddDays(-7));  
    } 
} 

猜你也可以在這裏使用一個接口的類的一個CreatedDate場/支撐

+0

謝謝!這有幫助。關鍵是不是創建一個Func,而是一個將更多邏輯添加到IQueryable對象中的擴展方法。 – Budda