C# 插入多列

C# 插入多列,c#,sql,ado.net,C#,Sql,Ado.net,我目前需要在数据库中插入一行,但我有很多列,总共11列(没有ID)。我正在使用以下命令: INSERT INTO table1 (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11) VALUES (@par1, @par2, @par3, @par4, @par5, @par6, @par7, @par8, @par9, @par10, @par11) 但正如您所看到的,它太长了,我无法避免

我目前需要在数据库中插入一行,但我有很多列,总共11列(没有ID)。我正在使用以下命令:

INSERT INTO table1 (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11) VALUES (@par1,  @par2,  @par3,  @par4,  @par5,  @par6,  @par7,  @par8,  @par9,  @par10,  @par11)

但正如您所看到的,它太长了,我无法避免使用列名,因为我仍然有ID。有没有更有效的方法来插入?或者是一种缩短它的方法?因为按照我的方式,我还必须一个接一个地添加参数,如下所示:

myCommand.Parameters.Add(value1, "@par1");

这与用任何其他语言填充任何数据结构的成员没有太大区别。如果没有填充数据结构的每个成员,则必须指定要填充的每个成员,是使用基于集合的方式(如SQL)指定它,还是使用单独的属性值对(如
set object.attribute=value


但是,与任何其他语言一样,您可以编写一个函数或过程来隐藏其中的一些细节,这样您只需要传入适当的变量。然后,对于任何给定场景,您只需写出一次所有详细代码。

将所有值放入一个列表,并使用for循环,然后在编辑中逐个插入列表值:

再次感谢@Sentinel提醒我注意潜在的安全风险。这种方法与语言无关,但我同意他的建议,即您也可以使用
myCommand.Parameters.Add(values[N],“@parN”)而不是为值构建字符串

扩展@Javies Inusti答案

这个答案假设您正在使用字符串来构建SQL查询

这是一个常见且易于处理的场景。最简单的处理方法(imho)是在字符串中使用标记,创建列和值的数组/列表,并用这些数组/列表的内容替换标记

using System;

class Program
{

    //defining a blacklist of unwanted terms that should not appear in your column names or value strings
    //This is just for the sake of the example, and there are definitely some statements missing in this array
    static string[] QUERY_BLACKLIST = { "SELECT", "DROP", "INSERT", "DELETE", "UPDATE" };

    static void Main(string[] args)
    {
    //Use markers in your query string
    string query = "INSERT INTO table (:columns:) VALUES (:values:);";
    //define an array of column names to insert for the :columns: marker
    string[] columns = { "ID", "Name", "Age", "Something"};
    //some dummy values. Real code would use a model or something to that effect
    int id = 9;
    string name = "John";
    int age = 12;
    bool something = true;
    //all values should be passed as strings, they will replace the :values: marker
    string[] values = { id.ToString(), name, age.ToString(), something.ToString()};
    query = Program.FillColumnsIntoQuery(query, columns, values);
    Console.WriteLine(query);
    //Output:
    //"INSERT INTO table (ID,Name,Age,Something) VALUES ('9','John','12','true');"

    //example for the blacklist check
    query = "INSERT INTO table (:columns:) VALUES (:values:);";
    //strings with malicious intent behind them
    string[] columns2 =  { "DROP table" };
    string[] values2 = { "DELETE * FROM table" };
    try
    {
        query = Program.FillColumnsIntoQuery(query, columns2, values2);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        //Output:
        //"Someone is trying to do evil stuff!"
    }

    Console.ReadLine();
    }

    public static string FillColumnsAndValuesIntoInsertQuery(string query, string[] colums, string[] values)
    {
    //joining the string arrays with a comma character
    string columnnames = string.Join(",", colums);
    //adding values with single quotation marks around them to handle errors related to string values
    string valuenames = "'" + string.Join("','", values) + "'"; ; 

    //we need to check every entry of the blacklist against the provided strings
    foreach(string blacklist in QUERY_BLACKLIST)
    {
        if(columnnames.ToLower().IndexOf(blacklist.ToLower()) >= 0
        || valuenames.ToLower().IndexOf(blacklist.ToLower()) >=0)
        {
            throw new Exception("Someone is trying to do evil stuff!");
        }
    }

    //replacing the markers with the desired column names and values
    return query.Replace(":columns:",columnnames).Replace(":values:", valuenames);
    }
}
如果您想变得有趣,可以为string类编写一个扩展方法。你也可以通过标记。您可以编写函数为您构建查询模板。您可以为函数选择一个较短的名称


可能性是无穷的:-)。

“但正如你所看到的,它太大了”-你这是什么意思?在什么意义上太大了?真的不清楚你在问什么。@JonSkeet我的意思是它很长,如果我有一个25列的数据库,它的效率很低。例如,只写一行并添加参数需要很长时间。你真的担心键入代码的效率,还是执行时间的效率?当然,如果你有很多值,那最终会变成更多的代码,但我并不认为这里有什么问题。@JonSkeet嗯,我假设我有有限的时间使用ADO.NET在数据库中进行基本操作,但是数据库有3个表,每个表都有很多列。这件事发生在我几周前,我正试图解决这个问题。在你花时间问这个问题的时候,你可能已经为insert语句编写了代码。说真的,如果这方面占了你整个应用程序编写时间的很大一部分,我会感到非常惊讶。我认为为了清晰起见,你应该用“列名”替换“值”。否则我会这样做。你需要小心使用动态SQL。恶意用户可能会提供破坏动态生成的查询的输入,从而产生意外结果。因此,最好保持查询参数化,但您仍然可以在数组中循环查找值,构建参数名称列表并使用
myCommand.parameters.Add(值[N],“@parN”)
将名称映射到参数。@Sentinel很好,我完全忘记了。为了安全起见,您可以尝试绝对确保列名和值字符串不包含任何类型的SQL语句。这实际上意味着一个额外的数组,在连接列和值之前循环遍历这些列和值,并针对不需要的术语的黑名单执行indexOf检查。这很重要,谢谢你提醒我。