如何使用Dapper清理动态表名?

时间:2017-06-01 17:07:07

标签: c# sql dapper

我是Dapper的新手,编写了一个将从提供的架构和表中提取的查询,以及使用动态排序和过滤。

Dapper使动态参数变得非常简单,但是,我不知道如何使用order by和where子句中的表来执行此操作。以下是我的方法,我看到了SQL注入的问题:

    public GridData GetGridData(string schema, string table, TableDataParameters tableDataParameters)
    {
        using (var dbConnection = VarConnection)
        {
            dbConnection.Open();

            if (!this.TableExists(dbConnection, schema, table))
            {
                throw new ItemNotFoundException($"Could not locate table {schema}.{table}.");
            }

            string orderyByClause = string.Join(",", tableDataParameters.SortModel.Select(s => $"[{s.ColId}] {(s.Sort.ToLower() == "asc" ? "asc" : "desc")}"));

            var parameters = new DynamicParameters();

            string whereClause; 
            if (tableDataParameters.FilterModel == null || !tableDataParameters.FilterModel.Any())
            {
                whereClause = "1=1";
            }
            else
            {
                whereClause = string.Join(" AND ", tableDataParameters.FilterModel.Select((fm, i) =>
                {
                    string whereParam = $"whereParam{i}";
                    parameters.Add(whereParam, fm.Filter);

                    if (fm.Operation == "startsWith")
                    {
                        return $"[{fm.Column}] LIKE @{whereParam} + '%'";
                    }
                    throw new InvalidOperationException($"Unsupported filter operation '{fm.Operation}'");
                }));
            }

            var query = $"SELECT COUNT(1) [total] " +
                        $"FROM [{schema}].[{table}] " +
                        $"WHERE {whereClause} " +
                        $"SELECT * " +
                        $"FROM [{schema}].[{table}] " +
                        $"WHERE {whereClause} " +
                        $"ORDER BY {orderyByClause} " + 
                        $"OFFSET {tableDataParameters.StartIndex.Value} ROWS " +
                        $"FETCH NEXT {tableDataParameters.StopIndex.Value - tableDataParameters.StartIndex.Value} ROWS ONLY";
            int total = 0;
            using (var reader = dbConnection.ExecuteReader(query, parameters)) 
            {
                //  First batch, it's the count
                if (reader.Read())
                {
                    total = reader.GetInt32(0);
                }

                var gridColumns = new List<GridColumn>();
                var gridRows = new List<string[]>();
                if (reader.NextResult() && reader.Read())
                {
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        string key = reader.GetName(i);
                        gridColumns.Add(new GridColumn(key, key, null, ""));
                    }

                    var items = new object[reader.FieldCount];
                    reader.GetValues(items);
                    gridRows.Add(items.Select(i => i.ToString()).ToArray());
                }

                while (reader.Read())
                {
                    var items = new object[reader.FieldCount];
                    reader.GetValues(items);
                    gridRows.Add(items.Select(i => i.ToString()).ToArray());
                }

                return new GridData(tableDataParameters.StartIndex.Value, tableDataParameters.StopIndex.Value, total, gridRows.Count(), gridColumns.ToArray(), gridRows.ToArray());
            }
        }
    }

我应该使用类似DbCommandBuilder.QuoteIdentifier的内容,https://msdn.microsoft.com/en-us/library/system.data.common.dbcommandbuilder.quoteidentifier(v=vs.110).aspx 在这种情况下?这似乎不会在这里有所帮助。

谢谢!

1 个答案:

答案 0 :(得分:1)

动态参数是矛盾的! Dapper使参数变得简单,但您不能对表名和列名进行参数化。这是SQL的限制,而不是短小精悍。如果你真的想这样做,你必须使用动态的sql和字符串方法,并且你自己就SQL注入而言。

如果你不这样做,你会更快乐,更长寿。这只是一条糟糕的道路。您没有增加太多价值,而且您可能会引入大量问题和限制。

您好像正在编写应用程序来浏览数据库。已经存在好的工具!