【问题标题】:Best practice for dynamically building variable length IN SQL clause in C#在 C# 中动态构建可变长度 IN SQL 子句的最佳实践
【发布时间】:2014-12-31 12:55:59
【问题描述】:

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

private readonly String _SELECT_UNEXPECTED_TOTES = "SELECT * FROM TABLE WHERE TABLE.Store IN ";

然后我执行以下操作(stores 是一个字符串数组,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 对象了解不多,据我所知,这个解决方案可能与简单的字符串替换一样糟糕......欢迎任何建议。

【问题讨论】:

  • 我不知道具体的方法适合你的情况,不过按照你的说法,你可以试试EntityFramework。
  • @IsThatSo 我正在处理的应用程序非常小。对于客户来说这是一项快速的工作,而且我认为,在观看了 Entity Framework 视频之后,Entity Framework 主要是矫枉过正。我不需要对这个应用程序中的数据库了解太多。它只是,获取ID列表,查询,然后吐出CSV。我希望有一个不需要复杂 API 的直截了当的解决方案。
  • 您的解决方案非常简单。加入字符串,您可以使用String.Join(", ", stores) 使您的代码“更好”。
  • 这里有一些很好的答案:stackoverflow.com/questions/43249/…
  • 你的代码可能很丑,但它确实避免了注入攻击。

标签: c# sql-server in-clause sqlparameter


【解决方案1】:

我认为没有更简单的方法可以通过 ADO.NET 做到这一点。但正如其他一些用户所提到的,Entity Framework 会使这变得相当干净,而且设置起来确实不难,尤其是在一个小应用程序上。它会将你上面的代码变成:

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

【讨论】:

    【解决方案2】:

    这里有一种更符合 LINQ 的方式来完成此操作:

    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 ...
    

    “魔法”是使用 Enumerable.Select<TSource, TResult> Method (IEnumerable<TSource>, Func<Source, Int32, TResult>) 重载,它使您可以访问索引以及 ID 数组中元素的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-03
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多