0

正常に動作するコードのスナップショットを次に示します。

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 オブジェクト (クエリ自体) を変更する代わりに、新しいデリゲートを結合し、クエリ式で使用した後です。

最適化されたコードを実行しようとすると、例外が発生します。

「Invoke(value(vfm_elita.ServiceLayer.DataLogicLayer.Messages.MessagesExtension+<>c_DisplayClass21+<> c_DisplayClass2c ).qAgeFilter, q.msg)」は SQL に変換できません。

質問:

  1. 私のコードの何が問題なのですか?

  2. 再利用可能なロジックを抽出して「フィルター」デリゲートを作成するために、ソース コードを最適化する方法を教えてください。

ありがとうございました

PS DB アクセス エンジンとして ASP.NET 4.0、MySQL 5.0、BLToolKit を使用しています。

4

1 に答える 1

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 フィールド/プロパティを持つクラスのインターフェイスをここで使用することもできると思います

于 2013-07-30T13:48:11.627 に答える