Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中动态构建SQL子句中可变长度的最佳实践_C#_Sql Server_In Clause_Sqlparameter - Fatal编程技术网

C# 在C中动态构建SQL子句中可变长度的最佳实践

C# 在C中动态构建SQL子句中可变长度的最佳实践,c#,sql-server,in-clause,sqlparameter,C#,Sql Server,In Clause,Sqlparameter,最近我发现自己在C中,做一些SQL。这不完全是我的专长领域。我写了一些看起来很难看的代码,但在任何地方都找不到更好的解决方案。这里的许多答案都会带来SQL注入风险,并且基本上都在以某种方式做我正在做的事情。情况是,我有一个表单,用户在表单中提供一个存储ID列表。当他们单击按钮时,将使用他们提供作为查询排除条件的存储生成CSV导出。我实现这一点的方法是将我的SQL字符串设置为常量,然后使用字符串生成器在in子句中动态附加@X。代码看起来相当糟糕,但这里有一个快速片段可以更好地解释。例如,假设SQL

最近我发现自己在C中,做一些SQL。这不完全是我的专长领域。我写了一些看起来很难看的代码,但在任何地方都找不到更好的解决方案。这里的许多答案都会带来SQL注入风险,并且基本上都在以某种方式做我正在做的事情。情况是,我有一个表单,用户在表单中提供一个存储ID列表。当他们单击按钮时,将使用他们提供作为查询排除条件的存储生成CSV导出。我实现这一点的方法是将我的SQL字符串设置为常量,然后使用字符串生成器在in子句中动态附加@X。代码看起来相当糟糕,但这里有一个快速片段可以更好地解释。例如,假设SQL查询是这样的

private readonly String _SELECT_UNEXPECTED_TOTES = "SELECT * FROM TABLE WHERE TABLE.Store IN ";
然后我做以下存储是一个字符串数组,sb是一个字符串生成器:

                //get enough room for all the stores
                var sqlParams = new SqlParameter[stores.Length];
                conn.Open();
                //append our query
                sb.Append(_SELECT_UNEXPORTED_TOTES);
                //open the IN list
                sb.Append("(");
                //build the in list
                int I = 0;
                foreach (String s in stores)
                {
                    sb.Append("@");
                    sb.Append(I);
                    sb.Append(",");
                    I++;
                }
                //trim the trailing ,
                sb.Length -= 1;
                sb.Append(")");
                //make the actual parameters
                I = 0;
                foreach (String s in stores)
                {
                    sqlParams[I] = new SqlParameter("@" + I, SqlDbType.VarChar);
                    sqlParams[I].Value = s;
                    I++;
                }

稍后在代码中,我将在SqlStatement对象中使用这些SQL参数。NET是否提供了更好的方法来实现这一点?我对.NETs SQL对象了解不多,据我所知,这个解决方案可能和简单的字符串替换一样糟糕。。。欢迎您提供任何建议。

我不认为通过ADO.NET有更简单的方法。但是,正如其他一些用户所提到的,实体框架将使其变得相当干净,而且安装起来并不困难,尤其是在小型应用程序上。它会将上述代码转换为:

var data = context.TABLE.Where(t => stores.Contains(t.Store)).ToList();

这里有一个更简单的方法来实现这一点:

string[] storeIds = { "1Store", "2Store", "RedStore", "BlueStore" };
using (SqlCommand cmd = new SqlCommand())
{
    var paras = storeIds.Select((store, index) => new
        {
            name = String.Format("@p{0}", index),
            value = store
        });
    StringBuilder sb = new StringBuilder();
    sb.Append("select * from myTable");
    sb.Append(" where myTable.storeid in (");
    sb.Append(String.Join(",", paras.Select(p => p.name).ToList()));
    sb.Append(")");
    cmd.CommandText = sb.ToString();
    foreach (var para in paras)
    {
        cmd.Parameters.AddWithValue(para.name, para.value);
    }
    cmd.Connection = conn;
    // Now do whatever you want with the command ...

神奇的是使用了重载,它使您能够访问索引以及ID数组中元素的值。

我不知道适合您情况的确切方法,但根据您的说法,您可以尝试EntityFramework。@因此我正在使用的应用程序非常小。对于客户来说,这是一项快速的工作,我认为,在观看实体框架视频之后,实体框架是一项重大的过火工作。我不需要对这个应用程序中的DB了解太多。它只是,得到一个ID的列表,查询,然后吐出CSV。我希望有一个简单的解决方案,不需要复杂的API。您的解决方案非常简单。连接字符串时,可以使用String.Join和stores来改进代码。这里有一些很好的答案:您的代码可能很难看,但它确实可以避免注入攻击。