2013-07-28 31 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