2016-03-19 4 views
0

J'essaye de construire une requête Linq vers Sql dynamique et ça marche plutôt bien, sauf pour invoquer la méthode SqlMethods.Like. Mon code est ci-dessous et le corps de la déclaration de LINQ généré ressemble à ceci:Linq dynamique utilisant SqlMethods.Like

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

Comme vous pouvez le voir, il tente d'appeler « Comme » sans la classe SqlMethods. Une idée de ce que je fais mal ??

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

Ne devrait pas être une propriété comme dans d'autres conditions? –

+0

Quelle est votre déclaration d'origine? –

+0

@IvanStoev Lorsque j'apporte cette modification, j'obtiens cette exception: LINQ to Entities ne reconnaît pas la méthode 'Boolean Like (System.String, System.String)', et cette méthode ne peut pas être traduite en expression de magasin. –

Répondre

0

Vous pouvez ignorer l'appel Like, et utiliser Contains, tous deux LINQ to SQL à Linq-entités et traduire correctement une déclaration LIKE. Vous sauvez même la citation! (qui, btw, vous faites mal).

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

En fait, l'opérateur 'Contient' n'est pas toujours suffisant. Par exemple, si vous voulez rechercher quelque chose comme ceci: 'first% last'. Le '%' dans la chaîne sera pris au lieu d'un caractère générique comme prévu. Pour utiliser l'opérateur 'SqlMethods.Like', vous pouvez utiliser ce qui suit:

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)); 
}