动态生成SQL查询

时间:2018-02-22 08:28:29

标签: c# sql winforms

我根据用户输入动态创建Textboxes,如下所示:

int nbrTextBoxBE = int.Parse(textBoxNbrBE.Text);
panelBE.Controls.Clear();
panelBE.Focus();
for (int i = 0; i < nbrTextBoxBE; i++)
{
    TextBox textBoxArticleCodeBE = new TextBox();
    TextBox textBoxDesignationBE = new TextBox();
    textBoxCArticleCodeBE.Name = "ArticleCodeBE" + (i + 1);
    textBoxDesignationBE.Name = "DesignationBE" + (i + 1);
    textBoxArticleCodeBE.Text = "";
    textBoxDesignationBE.Text = "";
    panelBE.Controls.Add(textBoxArticleCodeBE);
    panelBE.Controls.Add(textBoxDesignationBE);
    panelBE.Show();
}

使用按钮我想以这种形式将这些保存到我的数据库中:

INSERT INTO myTable (ArticleCode, Designation) VALUES (ArticleCodeBEi.Text, DesignationBEi.Text)

我尝试使用foreach循环:

foreach (TextBox tb in panelBE.Controls.OfType<TextBox>())
{
    // do stuff 
}

但当然它会产生我需要的查询数量的两倍。

3 个答案:

答案 0 :(得分:4)

执行任务的最正确方法是使用参数集

// This is assumed to be even
TextBox[] txtArray = panelBE.Controls.OfType<TextBox>().ToArray();

for(int x = 0; x < txtArray.Length; x+=2)
{
    TextBox tArticle = txtArray[x];
    TextBox tDesignation = txtArray[x+1];

    // Where you build the query text
    StringBuilder sb = new StringBuilder();

    // The placeholders for the parameters to be used
    List<string> prmNames = new List<string>();

    // The parameter collection 
    List<SqlParameter> prms = new List<SqlParameter>();

    // Initial text for the query
    sb.Append("INSERT INTO myTable (ArticleCode, Designation) VALUES (");

    prmNames.Add("@p" + tArticle.Name);
    prms.Add(new SqlParameter() 
    {
        ParameterName = "@p" + tArticle.Name,
        SqlDbType = SqlDbType.NVarChar,
        Value = tArticle.Text
    });
    prmNames.Add("@p" + tDesignation.Name);
    prms.Add(new SqlParameter()
    {
         ParameterName = "@p" + tDesignation.Name,
         SqlDbType = SqlDbType.NVarChar,
         Value = tDesignation.Text
    });

    // Concat the parameters placeholders and close the query text
    sb.Append(string.Join(",", prmNames) + ")");

    // Pass everything to an utility method
    // This could be part of a bigger utility database class
    ExecuteInsertInto(sb.ToString(), prms);
}

ExecuteInsertInto在哪里

private int ExecuteInsertInto(string query, List<SqlParameter> prms = null)
{
   using(SqlConnection cnn = new SqlConnection(..connectionstring goes here..))
   using(SqlCommand cmd = new SqlCommand(query))
   {
        cnn.Open();
        if(prms != null)
            cmd.Parameters.AddRange(prms.ToArray());
        return cmd.ExecuteNonQuery();
   }
}

请注意,这假设控件的检索顺序与在INSERT INTO字符串中写入字段的顺序相同。如果不是这种情况,那么您需要获取控件名称,子串控制名称以仅获取“BE”文本之前的文本,并将该字符串添加到StringBuilder实例。

  string fieldName = tb.Text.Substring(0, tb.Text.IndexOf("BE"));

还有一种更好的方法可以通过一次调用ExecuteInsertInto来传递每个命令,但确切的语法取决于数据库类型。简而言之,您可以构建具有许多插入的单个查询文本。对于Sql Server,请参阅 Multiple Insert Statements vs Single Inserts with multiple values

答案 1 :(得分:0)

虽然在这种情况下不是最干净的解决方案,但您可以使用正常的for循环轻松完成此操作;

var textboxes = panelBE.Controls.OfType<TextBox>();
for(int i=0; i < textboxes.length; i+=2)
{
   var articleCodeTextbox = textboxes[i];
   var designationCodeTextbox = textboxes[i+1];
   //build your query
}

当然这样做的危险在于panelBE控件中可能存在数量不均的文本框,导致您出现IndexOutOfBounds异常。 另一个危险是没有直接保证循环中的两个文本框确实彼此相关。

如果您想确定所有文本框都匹配,并降低IndexOutOfBounds异常的风险,您可以执行以下操作:

Dictionary<TextBox, TextBox> Textboxes = new Dictionary<TextBox, TextBox>();

int nbrTextBoxBE = int.Parse(textBoxNbrBE.Text);
panelBE.Controls.Clear();
panelBE.Focus();
for (int i = 0; i < nbrTextBoxBE; i++)
{
    TextBox textBoxArticleCodeBE = new TextBox();
    TextBox textBoxDesignationBE = new TextBox();
    textBoxCArticleCodeBE.Name = "ArticleCodeBE" + (i + 1);
    textBoxDesignationBE.Name = "DesignationBE" + (i + 1);
    textBoxArticleCodeBE.Text = "";
    textBoxDesignationBE.Text = "";
    panelBE.Controls.Add(textBoxArticleCodeBE);
    panelBE.Controls.Add(textBoxDesignationBE);
    Textboxes.Add(textBoxArticleCodeBE, textBoxDesignationBE);
    panelBE.Show();
}

然后,您可以简单地遍历所有ArticleCodeBE文本框的文本框,然后您可以从字典中提取附带的DesignationCodeBE文本框,如下所示:

foreach (TextBox articleCodeTB in panelBE.Controls.OfType<TextBox>().Where(tb => tb.Name.Contains("ArticleCodeBE")))
{
     var designationCodeTB = TextBoxes[articleCodeTB];
     //build your query  
}

在这种情况下,一个更好的更好的解决方案是在具有专用控件的正确视图模型的方向上做一些事情。你不必再担心匹配文本框了。

答案 2 :(得分:0)

怎么样:

foreach (TextBox tb in this.Controls.OfType<TextBox>().Where(textbox => textbox.Name.StartsWith("DesignationBE")))
{
    //do stuff
}