C# 使用通用字典向表中插入值

C# 使用通用字典向表中插入值,c#,asp.net,architecture,data-structures,data-access,C#,Asp.net,Architecture,Data Structures,Data Access,编码平台:ASP.NET 2.0 WebForms,以C#和MySQL为后端 背景 我目前正在修复一个网站的bug。 其中一个表“registrations”有80列 插入/更新是通过简单的sql语句完成的,没有任何参数化查询 问题 在注册时,用户可以改变许多参数,从而产生至少15种插入查询。我的问题是如何确保所有字段都插入了正确的值 所以,我创建了一个 Dictionary<string, string> fields = new Dictionary<string, str

编码平台:ASP.NET 2.0 WebForms,以C#和MySQL为后端

背景

我目前正在修复一个网站的bug。
其中一个表“registrations”有80列

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

问题

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

所以,我创建了一个

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));
我的问题是

  • 字典是实现这一点的最佳数据结构吗
  • 按通用字典对键进行排序是否会更改查询中的键值索引
  • 将所有键提取到一个数组中并将相应的值提取到另一个匹配数组中的最佳方法
  • 还有,还有哪些更好的方法

    注:我正在维护代码,并创建一个实体类,将列映射到属性,并存储值,这在这里不是一个选项。

    字符串列表(IEnumerable enumerable)
    
     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));
    
    { 列表=新列表(可枚举); 返回字符串.Join(“,”,list.ToArray()); } //... string sql=string.Format(“插入到注册({0})值({1})”, 列表(字段、键), 列表(字段.值));
    我知道描述中说您没有使用参数化sql,但是我知道,使用参数化sql是防止sql注入的更好方法。在txtLoginEmail中加入一些SQL并提交表单,对您的情况造成严重破坏,这根本不需要花费太多精力

    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(); } 私有静态字符串CreateInsertSql(字符串表, IDictionary参数映射) { var keys=parameterMap.keys.ToList(); //使用ToList()LINQ扩展方法,因为顺序不是 //每一个IDictionary实现都有保证 var sql=newstringbuilder(“插入”).Append(表).Append(“”); 对于(变量i=0;i SqlInsert("registrations", new Dictionary<string, string>() { { "LoginEmail", txtLoginEmail.Text }, { "Password", txtLoginPassword.Text }, { "ContactName", txtContactName.Text }, { City", txtCity.Text } }); SqlInsert(“注册”,新字典() { {“LoginEmail”,txtLoginEmail.Text}, {“Password”,txtLoginPassword.Text}, {“ContactName”,txtContactName.Text}, {City”,txtCity.Text} });
    我认为字典结构在这种情况下是可以的,但是

    按原样构建和执行字符串允许SQL注入数据包

    xkcd.com/327/利用妈妈

    我正在使用.NET3.5,但这个想法也可以应用于.NET2.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
    
    var值=新字典(){
    {“LoginEmail”,“LoginEmail”},
    {“密码”,“密码”},
    {“ContactName”,“ContactName”},
    {“城市”,“城市”}
    };
    System.Func key=p=>String.Concat(“?”,p);
    var语句=string.Format(“插入到注册({0})值({1})”,
    string.Join(“,”,values.values.ToArray()),
    string.Join(“,”,values.Keys.Select(key.ToArray())
    );
    //“在注册(登录邮箱、密码、联系人姓名、城市)中插入值(?登录邮箱、密码、联系人姓名、城市)”
    foreach(值中的var p){
    Add(key(p.key)、p.Value、SqlDbType.Text);
    }
    command.Prepare();
    command.ExecuteNonQuery();
    对于.NET mysql,它们可能是其他更好的类,如果是的话,很抱歉-我在.NET中没有使用mysql
    
    是的,
    中键的顺序与
    中相关值的顺序相同。请参阅.NET 4.0中的“备注”。我已更新了.NET 3.5的答案(
    使用System.Linq;
    )@mark:非常感谢,我最终在每个keyvaluepair上使用了foreach,并将键/值存储在两个数组中。在值中添加任何错误的charter都将导致错误,并且它将成为SQL注入的目标。谢谢。您的第一个函数可以在一行中编写。请参阅marks代码。此外,我使用的是C#2.0 True,但它的效率不如代码所使用的那么高s 2个StringBuilder实例(每个string.Join调用中有1个)和4个串联,在内存中创建3个不必要的字符串。我的使用单个StringBuilder创建0个不必要的字符串。此外,您不能使用string.Join在所有参数名称前面加上分隔符(?,在本例中)。抱歉,内存中有5个不必要的字符串,因为我忘记了字符串的结果字符串。Join calls。抱歉..死马。我认为这是避免SQL注入的最佳解决方案,但只有当您将Append(“?”)更改为Append(“@”)时,它才起作用。…好工作MySQL.SingleQuoteSQL注释所有单引号 SqlInsert("registrations", new Dictionary<string, string>() { { "LoginEmail", txtLoginEmail.Text }, { "Password", txtLoginPassword.Text }, { "ContactName", txtContactName.Text }, { City", txtCity.Text } });
    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