ahmed_sa Ответов: 3

Как сгенерировать параметризованный оператор insert для деталей с master master work, но без деталей ?


проблема

когда получить данные из json-файла для master it work, но детали не работают ?
{
   "master" : {
       "table" : "master_table",
       "fields" : {
           "name" : "bar",
           "address" : "fleet street",
           "phone" : "555"
       },
       "keys":{
           "id" : 1,
           "branch_id" : 1
       }      
   },
   "details" : [
       {
           "table": "detail1_table",
           "keys":{
               "id" : 1,
               "branch_id" : 1 ,
               "LineNumber" : 1
           },
           "fields" : {
               "ItemCode" : "item-5050",
               "Quantity" : 10 ,
               "Price" : 50 ,
               "Total" : 500
           }
       },
       {
           "table": "detail1_table",
            "keys":{
               "id" : 1,
               "branch_id" : 1 ,
               "LineNumber" : 2
           },
           "fields" : {
               "ItemCode" : "item-9050",
               "Quantity" : 5 ,
               "Price" : 20 ,
               "Total" : 100
           }
       }
   ]
}

Ожидаемый результат-3 заявления insert
// generated success

INSERT INTO master_table(id, branch_id, name, address, phone) VALUES(@id, @branch_id, @name, @address, @phone);

// generated problem

insert into detail1_table(id,branch_id,LineNumber,ItemCode,Quantity,Price,Total) values (@id,@branch_id,@LineNumber,@ItemCode,@Quantity,@Price,@Total)

// generated problem

insert into detail1_table(id,branch_id,LineNumber,ItemCode,Quantity,Price,Total) values (@id,@branch_id,@LineNumber,@ItemCode,@Quantity,@Price,@Total)
не генерировать

Что я уже пробовал:

public static class JsonHelper
    {
        public static string GetInsertStatement(JToken mastertoken)
        {
            return string.Format("INSERT INTO {0}({1}) VALUES({2});",
                mastertoken["table"],
                GetFieldParameterNames(mastertoken),
                GetFieldParameterNames(mastertoken, false));
        }

        static string GetFieldParameterNames(JToken mastertoken, bool fieldOnly = true)
        {
            string p = fieldOnly ? string.Empty : "@";
            return string.Concat(string.Join(", ", mastertoken["keys"].Cast<JProperty>().Select(jp => p + jp.Name)),
                ", ", string.Join(", ", mastertoken["fields"].Cast<JProperty>().Select(jp => p + jp.Name)));
        }

        public static List<SqlParameter> GetSqlParams(JToken mastertoken)
        {
            List<SqlParameter> para = new List<SqlParameter>();
            foreach (JToken jt in mastertoken["keys"])
                para.Add(new SqlParameter("@" + jt.ToObject<JProperty>().Name, jt.First));
            foreach (JToken jt in mastertoken["fields"])
                para.Add(new SqlParameter("@" + jt.ToObject<JProperty>().Name, jt.First));
            return para;
        }
        
        public static string GetInsertStatmentText(string JsonData)
        {
            string Insert = "";
            JObject jo = JObject.Parse(JsonData);
            JToken m = jo["master"];
            string connectionstring = "Server=sdfff-PC\\SQL2014;Database=sqlm;User Id=sa;Password=abc123;"; //change connection string
            using (SqlConnection connection = new SqlConnection(connectionstring))
            {
                using (SqlCommand command = new SqlCommand(JsonHelper.GetInsertStatement(m), connection))
                {
                    connection.Open();
                    List<SqlParameter> lsp = JsonHelper.GetSqlParams(jo["master"]);
                    foreach (SqlParameter sqp in lsp)

                        command.Parameters.Add(sqp);
                

                     Insert = command.CommandText;
                }
            }

            return Insert;

        }
        program.cs
        static void Main(string[] args)
        {

            
            string JsonData = File.ReadAllText("D:\\2.json");

            string insertStatment = JsonHelper.GetInsertStatmentText(JsonData);
        }

Richard Deeming

В вашем коде нет абсолютно ничего, что даже пытается взглянуть на details массив из файла JSON. Вы создаете команду для master возражайте, а потом остановитесь.

Почему вы ожидаете, что этот код будет генерировать команды вставки для записей в details массив?

3 Ответов

Рейтинг:
1

Patrice T

return string.Format("INSERT INTO {0}({1}) VALUES({2});",
    mastertoken["table"],
    GetFieldParameterNames(mastertoken),
    GetFieldParameterNames(mastertoken, false));

Не обязательно решение вашего вопроса, но у вас есть еще одна проблема.
Никогда не создавайте SQL-запрос путем объединения строк. Рано или поздно вы сделаете это с помощью пользовательских вводов, и это откроет дверь к уязвимости под названием "SQL-инъекция", она опасна для вашей базы данных и подвержена ошибкам.
Одна кавычка в имени - и ваша программа выйдет из строя. Если пользователь вводит имя, например "Брайан О'Коннер", может привести к сбою вашего приложения, это уязвимость SQL-инъекции, и сбой-это наименьшая из проблем, вредоносный пользовательский ввод, и он продвигается к командам SQL со всеми учетными данными.
SQL-инъекция - Википедия[^]
SQL-инъекция[^]
Атаки SQL-инъекций на примере[^]
PHP: SQL-инъекция - руководство пользователя[^]
Шпаргалка по предотвращению инъекций SQL - OWASP[^]
Как я могу объяснить SQL-инъекцию без технического жаргона? - Обмен Стеками Информационной Безопасности[^]


Richard Deeming

На самом деле, это не уязвимость SQLi. Код не вставляет этот параметр ценности; это вставка параметра имена.

Это код, который Мацей написал пару дней назад: https://www.codeproject.com/Answers/5164581/How-to-create-function-return-statement-insert-int[^]

Рейтинг:
0

MadMyche

Лучше всего для вас будет переосмыслить архитектуру этого здания.

Если бы это был мой проект, я бы так и сделал.:
1_. Несколько классов; каждый зеркального отображения таблицы базы данных
1А. Каждый из этих классов будет иметь собственных соответствующих методов это фигня

2. используйте стандартную библиотеку JSON (например, Newtonsoft) для сериализации и десериализации JSON в соответствующие классы

3. Создайте статический класс для доступа к базе данных.

Затем ваш пример кода просто возьмет полученный JSON, десериализует его в соответствующие классы, а затем вызовет соответствующую процедуру создания классов.



Обновление 1: добавление грубого класса в соответствии с "MasterTable"
public class Master {
    public int id { get; set; }
    public int branch_id { get; set; }
    public string name { get; set; }
    public string address { get; set; }
    public string phone { get; set; }

    public bool Save(Master mt) {
        bool Success = false;
        string connection = "your connection string retrieval method";
        string query = "INSERT master_table (id, branch_id, name, address, phone) VALUES (@id, @branch_id, @name, @address, @phone)";

        using (SqlConnection conn = new SqlConnection(connection)) {
            using (SqlCommand cmd = new SqlCommand(query, conn)) {
                cmd.CommandType = CommandType.Text;
                cmd.Parameters.AddWithValue("@id", mt.id);
                cmd.Parameters.AddWithValue("@branch_id", mt.branch_id);
                cmd.Parameters.AddWithValue("@name", mt.name);
                cmd.Parameters.AddWithValue("@address", mt.address);
                cmd.Parameters.AddWithValue("@phone", mt.phone);

                try {
                    conn.Open();
                    Success = (cmd.ExecuteNonQuery() == 1);
                }
                catch (Exception ex) { /* error handling routine */ }

                finally { conn.Close(); }
            }
        }
        return Success;
    }
}
И чтобы заполнить это, вы просто де-сериализуете свой JSON в объект. Это использование System.Web.Script.Serialization класс и это не для вашей конкретной строки JSON.
JavaScriptSerializer jss = new JavaScriptSerializer();
Master master = jss.Deserialize<Master>(JsonString);
И после этого вы можете вызвать метод save
bool saved = master.Save(master);


ahmed_sa

можете ли вы дать мне пример кода или ссылки на это пожалуйста или вы можете обратиться к json файлу выше если это возможно

MadMyche

Существует множество примеров на POCOs (#1) и десериализации JSON. Я не должен был бы писать код для вас

MadMyche

У меня действительно было немного свободного времени и я начал черновой код, чтобы вы начали

Рейтинг:
0

Richard Deeming

Ваш GetInsertStatmentText метод бесполезен. Вы не можете выполнить возвращаемую строку, потому что вам также нужны параметры.

Создать метод, чтобы генерировать и возвращать SqlCommand объект для вставки одного элемента из вашего JSON - файла:

public static SqlCommand CreateInsertCommand(SqlTransaction transaction, JToken token)
{
    var result = new SqlCommand();
    result.Connection = transaction.Connection;
    result.Transaction = transaction;
    
    result.CommandText = GetInsertStatement(token);
    result.CommandType = CommandType.Text;
    
    foreach (SqlParameter p in GetSqlParams(token))
    {
        result.Parameters.Add(p);
    }
    
    return result;
}
Затем создайте и выполните команды insert для токенов, которые вы хотите обработать. Вы захотите сделать это в рамках транзакции - либо все токены будут вставлены, либо ни один из них не будет вставлен.
static void InsertDataFromJson(JObject jsonData)
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();
        
        using (SqlTransaction transaction = connection.BeginTransaction())
        {
            using (SqlCommand command = CreateInsertCommand(transaction, jsonData["master"]))
            {
                command.ExecuteNonQuery();
            }
            
            JArray detailsList = (JArray)jsonData["details"];
            foreach (JToken details in detailsList)
            {
                using (SqlCommand command = CreateInsertCommand(transaction, details))
                {
                    command.ExecuteNonQuery();
                }
            }
            
            transaction.Commit();
        }
    }
}


ahmed_sa

Большое вам спасибо за помощь и поддержку, когда я его выполняю
Сопоставление не существует для объекта типа Newtonsoft.Json.Linq.JValue к известному собственному типу управляемого поставщика
так вот как решить эту ошибку, пожалуйста ?

Richard Deeming

Вот в этом-то и проблема. GetSqlParams метод. Попробуйте изменить его на:

public static List<SqlParameter> GetSqlParams(JToken mastertoken)
{
    List<SqlParameter> para = new List<SqlParameter>();
    foreach (JToken jt in mastertoken["keys"])
    {
        para.Add(new SqlParameter("@" + jt.ToObject<JProperty>().Name, jt.First.ToObject<JValue>().Value));
    }
    foreach (JToken jt in mastertoken["fields"])
    {
        para.Add(new SqlParameter("@" + jt.ToObject<JProperty>().Name, jt.First.ToObject<JValue>().Value));
    }
    
    return para;
}
Важной частью является замена jt.First с jt.First.ToObject<JValue>().Value.