根据过滤条件生成动态 SQL 查询

问题描述

我们要求客户可以根据特定条件过滤记录。

以下是我在控制器中获得的示例过滤条件

[
   {
      "Field":"BANKNAME","Operator":"=","Value":"35","Conditionoperator":"OR","DField":"N"
   },{
      "Field":"BANKNAME","Value":"15","Conditionoperator":"AND",{
      "Field":"PTLOCATION","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 && FilterCondition.Count == 1)
    {
        filterCondition += " custom.CustomeFieldName ='" + lstFilterCondition[i].Field + "' and custom.FIELDVALUE " + lstFilterCondition[i].Operator + "'" + lstFilterCondition[i].Value + "' ";
    }
    else if (i == 0 && !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) 

解决方法

如评论中所述,该代码易受 SQL 注入攻击。

另一种选择是使用 ORM,例如EF 并编写您自己的“引擎”以从自定义查询模型转换为 LINQ - https://docs.microsoft.com/en-us/ef/core/querying/

更简单的选择可能是使用 OData,它支持用户定义的开箱即用查询,并连接到 EF - https://docs.microsoft.com/en-us/odata/webapi/getting-startedhttps://docs.microsoft.com/en-us/odata/client/query-options