Генерировать динамический SQL-запрос на основе критериев фильтрации

#c# #asp.net #.net #asp.net-mvc #asp.net-core

#c# #asp.net #.net #asp.net-mvc #asp.net-ядро

Вопрос:

У нас есть требование, согласно которому клиент может фильтровать записи на основе определенных условий.

Ниже приведен пример условия фильтра, которое я получаю в контроллере

 [
   {
      "Field":"BANKNAME",
      "Operator":"=",
      "Value":"35",
      "ConditionOperator":"OR",
      "DField":"N"
   },
   {
      "Field":"BANKNAME",
      "Operator":"=",
      "Value":"15",
      "ConditionOperator":"AND",
      "DField":"N"
   },
   {
      "Field":"PTLOCATION",
      "Operator":"=",
      "Value":"261",
      "ConditionOperator":" ",
      "DField":"Y"
   ]
 

На основе условия фильтра мы генерируем SQL-запрос, ниже приведен код, который мы пробовали

 var FilterCondition = JsonConvert.DeserializeObject<List<RptFilterCondition>>(filter);
string filterCondition = string.Empty;
var lstFilterCondition = FilterCondition.Where(a => a.DField == "N").ToList();
for (int i = 0; i < lstFilterCondition.Count; i  )
{
    if (i == 0 amp;amp; FilterCondition.Count == 1)
    {
        filterCondition  = " custom.CustomeFieldName ='"   lstFilterCondition[i].Field   "' and custom.FIELDVALUE "   lstFilterCondition[i].Operator   "'"   lstFilterCondition[i].Value   "' ";
    }
    else if (i == 0 amp;amp; !isanycondition)
    {
        filterCondition  = " (custom.CustomeFieldName ='"   lstFilterCondition[i].Field   "' and custom.FIELDVALUE "   lstFilterCondition[i].Operator   "'"   lstFilterCondition[i].Value   "' )"   lstFilterCondition[i].ConditionOperator;
    }
    else if (i == FilterCondition.Count - 1)
    {
        filterCondition  = " (custom.CustomeFieldName='"   lstFilterCondition[i].Field   "'  and custom.FIELDVALUE "   lstFilterCondition[i].Operator   "'"   lstFilterCondition[i].Value   "' )";
    }
    else
    {
        filterCondition  = " (custom.CustomeFieldName='"   lstFilterCondition[i].Field   "'  and custom.FIELDVALUE"   lstFilterCondition[i].Operator   "'"   lstFilterCondition[i].Value   "' )"   lstFilterCondition[i].ConditionOperator;
    }
}

return filterCondition;
 

Ниже сгенерировано условие фильтра

 (custom.CustomeFieldName ='BANKNAME' and custom.FIELDVALUE ='35') OR 
(custom.CustomeFieldName='BANKNAME'  and custom.FIELDVALUE='15')
and (PTLOCATION = 261) 
 

Ниже ожидается, что для одинаковых имен полей должна быть круглая скобка

 ((custom.CustomeFieldName ='BANKNAME' and custom.FIELDVALUE ='35') OR 
(custom.CustomeFieldName='BANKNAME'  and custom.FIELDVALUE='15'))
and (PTLOCATION = 261) 
 

Комментарии:

1. Это похоже на ожидающую атаки sql-инъекции

2. @00110001 можете ли вы предложить мне лучший способ сделать с вышеуказанной логикой, я попытаюсь реализовать то же самое

3. custom.CustomeFieldName custom.FIELDVALUE ? Итак, у вас есть таблица пользовательских полей, где каждое поле хранится в виде строки? Означает ли это, что вам нужно and exists(select 1 from ....) обходить каждый тест?

Ответ №1:

Как упоминалось в комментарии, код уязвим для SQL-инъекции.

Одной из альтернатив является использование ORM, например EF, и написать свой собственный «движок» для перевода из пользовательской модели запросов в LINQ — https://docs.microsoft.com/en-us/ef/core/querying /

Более простым вариантом может быть использование OData, который поддерживает пользовательские запросы «из коробки» с подключением к EF — https://docs.microsoft.com/en-us/odata/webapi/getting-started , https://docs.microsoft.com/en-us/odata/client/query-options