Вставка значений в таблицу с использованием универсального словаря - PullRequest
4 голосов
/ 17 апреля 2011

Платформа кодирования: ASP.NET 2.0 WebForms с C # с MySQL в качестве бэкэнда

Фон

В настоящее время я работаю над исправлением ошибки на сайте.
Одна из таблиц «регистрации» имеет 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 .: Я поддерживаю код и создаю класс сущностей, сопоставляя столбцы со свойствами и сохраняя значения, не вариант в этом.

Ответы [ 3 ]

11 голосов
/ 17 апреля 2011
 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));
2 голосов
/ 17 апреля 2011

Я думаю, что структура словаря в этом случае в порядке, но

сборка и выполнение строки в том виде, в каком она есть, допускает атаки SQL Injection

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
1 голос
/ 17 апреля 2011

Я знаю, что в описании говорится, что вы не используете параметризованный 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 }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...