2013-06-01 5 views
1

Мне интересно, как избежать кавычек в LINQ to Entities.Quotes escape in Where в LINQ to Entites

Это моя среда: Entity Framework 5 с Silverlight 5 и WCF RIA Services, MySQL 5.6 и MySQLConnector 6.5.6.

У меня есть следующий запрос:

DomainContext.Load<Product>(DomainContext.GetProductQuery() 
             .Where<Product>(p => p.name.Contains(parameter)) 
             .Take<Product>(30)); 

Если переменная параметр содержит цитату ' это вызывает исключение ошибок синтаксиса MySQL. Независимо от метода (StartWith, Contains) он всегда вызывает исключение.

Это делает то же самое, используя FilterDescriptor с DomainDataSource.

Важное примечание: Это не вызывает каких-либо исключений с символами как % или двойные кавычки ". Также он не вызывает никаких исключений с простой цитатой, если оператор равен строгим следующим образом.

DomainDataSource.FilterDescriptors.Add(new FilterDescriptor("productName", FilterOperator.IsEqualTo, SelectedProductName)); 

или

DomainContext.Load<Product>(DomainContext.GetProductQuery() 
             .Where<Product>(p == parameter) 
             .Take<Product>(30)); 

У меня нет никаких трудностей для вставки данных.

Любая помощь будет очень признательна. Спасибо.

Обновление: Я забыл упомянуть некоторые вещи.

Это мой метод со стороны обслуживания.

public IQueryable<Product> GetProduct() 
{ 
    return this.ObjectContext.product; 
} 

Как я могу защитить это от инъекций SQL? Должен ли я писать десятки строк кода для управления фильтрами?

EDIT: Проблема решена в последней версии поставщика MySQL для EF.

+0

Вы уверены, что ** вам нужно ** так много ** текста ** жирным шрифтом **? Пожалуйста ** рассмотрите ** редактировать, чтобы уменьшить количество ** выделенного ** текста. – abatishchev

+0

Я использую жирный текст, чтобы сфокусироваться на ключевых словах. Поэтому я думаю, что да, мне это нужно. – Frank

ответ

0

Я нашел обходной путь для этой проблемы.

Во-первых, я хотел бы поблагодарить tomlev от www.developpez.net для его решения, как chamamo за его помощь тоже.

Это прямая ссылка на обсуждение на французском http://www.developpez.net/forums/d1349604/services-web/wcf-ria-services-injection-sql/

Это исходный код обертки, чтобы решить эту проблему.

class MySqlQueryableWrapper<T> : IQueryable<T> 
{ 
    private readonly IQueryable<T> _queryable; 
    private readonly IQueryProvider _provider; 

    public MySqlQueryableWrapper(IQueryable<T> queryable) 
    { 
     _queryable = queryable; 
     _provider = new MySqlQueryProviderWrapper(queryable.Provider); 
    } 

    public Type ElementType 
    { 
     get { return _queryable.ElementType; } 
    } 

    public Expression Expression 
    { 
     get { return _queryable.Expression; } 
    } 

    public IQueryProvider Provider 
    { 
     get { return _provider; } 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return _queryable.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

class MySqlQueryProviderWrapper : IQueryProvider 
{ 
    private readonly MySqlExpressionFixer _visitor = new MySqlExpressionFixer(); 
    private readonly IQueryProvider _provider; 

    public MySqlQueryProviderWrapper(IQueryProvider provider) 
    { 
     _provider = provider; 
    } 

    public IQueryable CreateQuery(Expression expression) 
    { 
     return _provider.CreateQuery(_visitor.Visit(expression)); 
    } 

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression) 
    { 
     return _provider.CreateQuery<TElement>(_visitor.Visit(expression)); 
    } 

    public object Execute(Expression expression) 
    { 
     return _provider.Execute(_visitor.Visit(expression)); 
    } 

    public TResult Execute<TResult>(Expression expression) 
    { 
     return _provider.Execute<TResult>(_visitor.Visit(expression)); 
    } 

} 

class MySqlExpressionFixer : ExpressionVisitor 
{  
    protected override Expression VisitMethodCall(MethodCallExpression node) 
    { 
     if ((node.Method.Name == "Contains" || node.Method.Name == "StartsWith") && 
      node.Method.DeclaringType == typeof(string) && 
      node.Arguments.Count == 1) 
     { 
      var c = node.Arguments[0] as ConstantExpression; 
      if (c != null) 
      { 
       string s = c.Value as string; 
       if (s != null) 
       { 
        s = s.Replace("'", "''"); 
        node = Expression.Call(node.Object, node.Method, Expression.Constant(s)); 
       } 
      } 
     } 

     return base.VisitMethodCall(node); 
    } 
} 

Вот пример.

public IQueryable<Product> GetProduct() 
{ 
    return new MySqlQueryableWrapper<Product>(this.ObjectContext.product); 
} 
+0

Я сообщил об этой ошибке. Эта проблема решается в последней версии поставщика MySQL. – Frank

0

Для быстрого решения для вашей конкретной проблемы:

string cleanParameter = parameter.Replace("'", "\'") 

ИЛИ

Посмотрите here для более общего решения, которое описывает C# эквивалент mysql_real_escape_string.

string cleanParameter = MySQLEscape(parameter) 

MySQLEscape, как описано в упомянутой статье:

private static string MySQLEscape(string str) 
{ 
    return Regex.Replace(str, @"[\x00'""\b\n\r\t\cZ\\%_]", 
     delegate(Match match) 
     { 
      string v = match.Value; 
      switch (v) 
      { 
       case "\x00":   // ASCII NUL (0x00) character 
        return "\\0"; 
       case "\b":    // BACKSPACE character 
        return "\\b"; 
       case "\n":    // NEWLINE (linefeed) character 
        return "\\n"; 
       case "\r":    // CARRIAGE RETURN character 
        return "\\r"; 
       case "\t":    // TAB 
        return "\\t"; 
       case "\u001A":   // Ctrl-Z 
        return "\\Z"; 
       default: 
        return "\\" + v; 
      } 
     }); 
} 

Side Примечание: код звучит, как он может быть подвержен атак внедрения SQL. (Я не могу сказать без лишнего контекста). В этом article описано, что такое SQL-инъекции и как их предотвратить.

+0

Согласен. Но если EntityFramework будет использовать параметризованные запросы, этого не произойдет. Вот почему я хотел знать, есть ли какие-либо решения, чтобы заставить EF использовать подобные запросы в любое время. Спасибо за образец кода. – Frank

+0

Я редактировал свой пост. Я забыл немного вещей. – Frank

+0

Вы можете использовать лямбда как 'Regex.Replace (str," ... ", match => {...})' – abatishchev

Смежные вопросы