2016-03-19 18 views
0

動的なLinq to Sqlクエリを作成しようとしていますが、SqlMethods.Likeメソッドを呼び出す以外はかなりうまくいきます。私のコードは以下の通りですとLINQ文の本体は、次のようになりますが、生成された:あなたが見ることができるようにSqlMethods.Likeを使用した動的Linq

Body = {((((log.ClientCode == "C1") OrElse 
(log.ClientCode == "C2")) AndAlso 
(log.Source == "S1")) AndAlso Like("Message", "%1%"))} 

は、それがSqlMethodsクラスなし「のように」呼び出そうと。私が間違って何をしているのか何か考え??

public IEnumerable<ILog> Get(int pageNumber, int pageCount, 
     List<string> clientCodes, List<string> sources, List<LogLevel> logLevels, 
     string messageContains, string userNameContains, 
     DateTime? dateStart, DateTime? dateEnd) 
    { 
     var expressions = new List<Expression>(); 

     ParameterExpression pe = Expression.Parameter(typeof(Data.Logging.Log), "log"); 

     if (clientCodes != null && clientCodes.Count > 0) 
     { 
      expressions.Add(CreateClientCodeExpression(pe, clientCodes)); 
     } 
     if (sources != null && sources.Count > 0) 
     { 
      expressions.Add(CreateSourceExpression(pe, sources)); 
     } 

     if (logLevels != null && logLevels.Count > 0) 
     { 
      expressions.Add(CreateLogLevelExpression(pe, logLevels)); 
     } 

     if (!string.IsNullOrWhiteSpace(messageContains)) 
     { 
      expressions.Add(CreateMessageExpression(pe, messageContains)); 
     } 

     Expression exp = null; 
     if (expressions.Count > 0) 
     { 
      exp = expressions[0]; 
     } 
     for (var i = 1; i < expressions.Count; i++) 
     { 
      exp = Expression.AndAlso(exp, expressions[i]); 
     } 

     var predicate = Expression.Lambda<Func<Data.Logging.Log, bool>>(exp, pe); 
     var results = DbContext.Logs.Where(predicate).ToList(); 

     foreach (var result in results) 
     { 
      yield return ConvertDbLogToLog(result); 
     } 
    } 

    private Expression CreateClientCodeExpression(ParameterExpression pe, List<string> clientCodes) 
    { 
     Expression result = null; 
     clientCodes.ForEach(cc => 
     { 
      MemberExpression me = Expression.Property(pe, "ClientCode"); 
      ConstantExpression ce = Expression.Constant(cc); 

      if (result == null) { result = Expression.Equal(me, ce); } 
      else { result = Expression.OrElse(result, Expression.Equal(me, ce)); } 
     }); 

     return result; 
    } 

    private Expression CreateSourceExpression(ParameterExpression pe, List<string> sources) 
    { 
     Expression result = null; 
     sources.ForEach(s => 
     { 
      MemberExpression me = Expression.Property(pe, "Source"); 
      ConstantExpression ce = Expression.Constant(s); 

      if (result == null) { result = Expression.Equal(me, ce); } 
      else { result = Expression.OrElse(result, Expression.Equal(me, ce)); } 
     }); 

     return result; 
    } 

    private Expression CreateLogLevelExpression(ParameterExpression pe, List<LogLevel> logLevels) 
    { 
     Expression result = null; 
     logLevels.ForEach(l => 
     { 
      MemberExpression me = Expression.Property(pe, "LogLevel"); 
      ConstantExpression ce = Expression.Constant(l.ToString()); 

      if (result == null) { result = Expression.Equal(me, ce); } 
      else { result = Expression.OrElse(result, Expression.Equal(me, ce)); } 
     }); 

     return result; 
    } 

    private MethodCallExpression CreateMessageExpression(ParameterExpression pe, string message) 
    { 
     return Expression.Call(typeof(SqlMethods).GetMethod("Like", new[] { typeof(string), typeof(string) }), 
      Expression.Constant("Message"), Expression.Constant(string.Format("%{0}%", message))); 
    } 
+0

他の条件のように「メッセージ」を指定しないでください。 –

+0

元の声明は何ですか? –

+0

@IvanStoevこの変更を加えると、LINQ to Entitiesが 'Boolean Like(System.String、System.String)'メソッドを認識せず、このメソッドをストア式に変換できません。 –

答えて

0

あなたは正しくLIKEの文に変換されLINQの-SQL-へとLINQのツーエンティティの両方、Like呼び出しをスキップし、Containsを使用することができます。あなたは引用を保存することさえできます! (btw、あなたは間違っている)。

private MethodCallExpression CreateMessageExpression(ParameterExpression pe, string message) 
{ 
    return Expression.Call(Expression.Property(pe, "Message"), "Contains", null, Expression.Constant(message)); 
} 
1

実際には、 'Contains'演算子は必ずしも十分ではありません。たとえば、次のような検索をしたいとします。 'first%last'。文字列中の '%'は、意図したとおりのワイルドカードの代わりに文字通り取られます。 'SqlMethods.Like'演算子を使用するには、次のものを使用できます。

public static MethodCallExpression Like(this ParameterExpression pe, string value) 
{ 
    var prop = Expression.Property(pe, pe.Name); 
    return Expression.Call(typeof(SqlMethods), "Like", null, prop, Expression.Constant(value)); 
} 
関連する問題