使用通用字典将值插入表中

时间:2011-04-17 17:19:57

标签: c# asp.net architecture data-structures data-access

编码平台:使用C#和ASP.NET作为后端的ASP.NET 2.0 WebForms

背景

我目前正在处理修复网站的错误 其中一个表“注册”有80列。

插入/更新是通过简单的sql语句完成的,没有任何参数化查询。

问题

在注册时,用户可以改变许多参数,从而导致至少15种INSERT查询。我的问题是如何确保插入所有字段的正确值。

所以,我创建了一个

Dictionary<string, string> fields = new Dictionary<string, string>();

fields.Add("LoginEmail", MySQL.SingleQuoteSQL(txtLoginEmail.Text));
fields.Add("Password", MySQL.SingleQuoteSQL(txtLoginPassword.Text));

fields.Add("ContactName", MySQL.SingleQuoteSQL(txtContactName.Text));
fields.Add("City", MySQL.SingleQuoteSQL(txtCity.Text));

我的想法是制作一个像这样的简单插入查询

INSERT INTO registrations("all keys as comma separated string") VALUES ("all keys as comma separated string") 

我的问题是

  1. Dictionary是实现此目的的最佳数据结构吗?
  2. 通用字典对键进行排序是否会更改查询中的键值索引?
  3. 将所有键提取到数组中的最佳方法,以及将相应值提取到另一个匹配数组。
  4. 而且,还有哪些更好的方法?

    P.S:我正在维护代码并使实体类将列映射到属性并存储值不是一个选项。

3 个答案:

答案 0 :(得分:11)

 string list<T>(IEnumerable<T> enumerable)
 {
   List<T> list = new List<T>(enumerable);
   return string.Join(",", list.ToArray());
 } 

//...
string sql= String.Format("INSERT INTO registrations({0}) VALUES({1})",
                list(fields.Keys),
                list(fields.Values));

答案 1 :(得分:2)

我认为字典结构在这种情况下可以,但是

构建和执行字符串,允许SQL注入atacks

xkcd.com/327/对妈妈的剥削

我使用的是.NET 3.5,但这个想法也适用于.NET 2.0

如果MySQL.SingleQuoteSQL的功能超出了它的名称,那么请告诉我

否则将值添加为参数以防止此

var values = new Dictionary<string, string>() {
  {"LoginEmail", "LoginEmail"},
  {"Password", "Password"},
  {"ContactName", "ContactName"},
  {"City", "City"}
};

System.Func<string, string> key = p => String.Concat("?", p);

var statement = string.Format("INSERT INTO registrations ({0}) VALUES ({1})", 
  string.Join(",", values.Values.ToArray()),
  string.Join(",", values.Keys.Select(key).ToArray())
);

//"INSERT INTO registrations (LoginEmail,Password,ContactName,City) VALUES (?LoginEmail,?Password,?ContactName,?City)"  

foreach(var p in values) {
  command.Parameters.Add(key(p.Key), p.Value, SqlDbType.Text);
}

command.Prepare();
command.ExecuteNonQuery();

They may be other better classes for .NET mysql, apologies if so - I haven't used mysql in .NET

答案 2 :(得分:1)

我知道描述说你没有使用参数化的sql,但是恕我直言,使用参数化的sql是一种更好的方法来防止sql注入。将一些SQL抛入txtLoginEmail并提交表格会对您的情况造成严重破坏并不需要花费太多精力。

private static string CreateInsertSql(string table, 
                                      IDictionary<string, string> parameterMap)
{
    var keys = parameterMap.Keys.ToList();
    // ToList() LINQ extension method used because order is NOT
    // guaranteed with every implementation of IDictionary<TKey, TValue>

    var sql = new StringBuilder("INSERT INTO ").Append(table).Append("(");

    for (var i = 0; i < keys.Count; i++)
    {
        sql.Append(keys[i]);
        if (i < keys.Count - 1)
            sql.Append(", ");
    }

    sql.Append(") VALUES(");

    for (var i = 0; i < keys.Count; i++)
    {
        sql.Append('?').Append(keys[i]);
        if (i < keys.Count - 1)
            sql.Append(", ");
    }

    return sql.Append(")").ToString();
}
private static void SqlInsert(string table, IDictionary<string, string> parameterMap)
{
    using (var connection = AcquireConnection())
    {
        connection.Open();
        using (var command = connection.CreateCommand())
        {
            command.Connection = connection;
            command.CommandText = CreateInsertSql(table, parameterMap);
            foreach (var pair in parameterMap)
                command.Parameters.Add(pair.Key, pair.Value);
            command.ExecuteNonQuery();
        }
    }
}

调用类似于:

SqlInsert("registrations", new Dictionary<string, string>()
{
    { "LoginEmail", txtLoginEmail.Text },
    { "Password", txtLoginPassword.Text },
    { "ContactName", txtContactName.Text },
    { City", txtCity.Text }
});