【问题标题】:Inserting values to a table using generic dictionary使用通用字典向表中插入值
【发布时间】:2011-08-07 09:26:33
【问题描述】:

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

背景

我目前正在修复网站的错误。
其中一张“registrations”表有 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. 将所有键提取到一个数组中并将对应值提取到另一个匹配数组的最佳方法。

另外,还有哪些更好的方法?

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

【问题讨论】:

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


    【解决方案1】:
     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));
    

    【讨论】:

    • 是的,Keys 中键的顺序与Values 中的关联值相同。见msdn.microsoft.com/en-us/library/yt2fy5zk.aspx中的“备注”
    • 我假设是 .NET 4.0。我已经更新了 .NET 3.5 (using System.Linq;) 的答案。
    • @mark: 非常感谢我最终在每个键值对上 foreach 并将键/值存储在两个数组中
    • 在值中添加任何错误的租船者将导致错误,并将成为 SQL 注入的目标。
    【解决方案2】:

    我知道描述说您没有使用参数化 sql,但恕我直言,使用参数化 sql 是防止 sql 注入的更好方法。将一些 SQL 放入 txtLoginEmail 并提交对您的情况造成严重破坏的表单根本不需要太多努力。

    私有静态字符串 CreateInsertSql(字符串表, IDictionary parameterMap) { var keys = parameterMap.Keys.ToList(); // ToList() 使用 LINQ 扩展方法,因为 order 不是 // 保证 IDictionary 的每个实现 var sql = new StringBuilder("INSERT INTO ").Append(table).Append("("); for (var i = 0; i private static void SqlInsert(string table, IDictionary parameterMap) { 使用 (var connection = AcquireConnection()) { 连接.打开(); 使用 (var command = connection.CreateCommand()) { command.Connection = 连接; command.CommandText = CreateInsertSql(table, parameterMap); foreach(parameterMap 中的 var 对) command.Parameters.Add(pair.Key, pair.Value); command.ExecuteNonQuery(); } } }

    调用类似于:

    SqlInsert("注册", new Dictionary() { { "LoginEmail", txtLoginEmail.Text }, { "密码", txtLoginPassword.Text }, { "ContactName", txtContactName.Text }, { 城市", txtCity.Text } });

    【讨论】:

    • 谢谢。你的第一个函数可以写成一行。见标记代码。我也在使用 C# 2.0
    • 是的,但它会降低效率,因为该代码使用 2 个 StringBuilder 实例(每个 string.Join 调用中的 1 个)和 4 个串联在内存中创建 3 个不必要的字符串。我的利用单个 StringBuilder 创建 0 个不必要的字符串。
    • 另外,您不能使用 string.Join 为所有参数名称添加前缀(在本例中为?)。
    • 抱歉,内存中有 5 个不必要的字符串,因为我忘记了 string.Join 调用的结果字符串。对不起..死马。
    • 我认为这是防止 SQL 注入的最佳解决方案,但只有将 Append('?') 更改为 Append('@').. 干得好
    【解决方案3】:

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

    按原样构建和执行字符串允许 SQL 注入攻击

    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
    

    【讨论】:

    • MySQL.SingleQuoteSQL 获取所有单引号
    猜你喜欢
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2015-06-10
    • 1970-01-01
    相关资源
    最近更新 更多