Click here to Skip to main content
15,896,606 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
problem

when get data from json file for master it work but details not 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
           }
       }
   ]
}

Expected Result is 3 statement 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)
not generated

What I have tried:

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);
        }
Posted
Updated 15-Aug-19 7:59am
v3
Comments
Richard Deeming 15-Aug-19 13:41pm    
There is absolutely nothing in your code which even attempts to look at the details array from the JSON file. You build a command for the master object, and then stop.

Why would you expect that code to generate insert commands for the records in the details array?

Best thing for you to do is going to rethink the architecture of this.

If this was my project, I would have:
1_. Multiple classes; each one mirroring a database table
1a. Each of these classes would have it's own respective CRUD methods

2. Use a standard JSON library (such as Newtonsoft) to serialize and deserialize JSON to the proper classes

3. Create a static class for database access.

Your sample code would then just take the received JSON, deserialize it to respective classes, and then call the respective classes Create routine.


Update 1: adding a rough class to match the "MasterTable"
C#
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;
    }
}
And to populate this, you would simply de-serialize your JSON into the object. This is using the System.Web.Script.Serialization class and it is not for your particular JSON string.
C#
JavaScriptSerializer jss = new JavaScriptSerializer();
Master master = jss.Deserialize<Master>(JsonString);
And after that you could call the save method
bool saved = master.Save(master);
 
Share this answer
 
v2
Comments
ahmed_sa 15-Aug-19 3:33am    
can you give me sample code or links about that please or you can applying to json file above if possible
MadMyche 15-Aug-19 7:02am    
There are plenty of samples on POCOs (#1) and deserializing JSON. I should not have to write the code for you
MadMyche 15-Aug-19 17:56pm    
I did have some free time and started some rough code to get you started
C#
return string.Format("INSERT INTO {0}({1}) VALUES({2});",
    mastertoken["table"],
    GetFieldParameterNames(mastertoken),
    GetFieldParameterNames(mastertoken, false));

Not necessary a solution to your question, but another problem you have.
Never build an SQL query by concatenating strings. Sooner or later, you will do it with user inputs, and this opens door to a vulnerability named "SQL injection", it is dangerous for your database and error prone.
A single quote in a name and your program crash. If a user input a name like "Brian O'Conner" can crash your app, it is an SQL injection vulnerability, and the crash is the least of the problems, a malicious user input and it is promoted to SQL commands with all credentials.
SQL injection - Wikipedia[^]
SQL Injection[^]
SQL Injection Attacks by Example[^]
PHP: SQL Injection - Manual[^]
SQL Injection Prevention Cheat Sheet - OWASP[^]
How can I explain SQL injection without technical jargon? - Information Security Stack Exchange[^]
 
Share this answer
 
Comments
Richard Deeming 15-Aug-19 13:36pm    
Actually, it's not a SQLi vulnerability. The code isn't inserting the parameter values; it's inserting the parameter names.

It's code that Maciej wrote a couple of days ago: https://www.codeproject.com/Answers/5164581/How-to-create-function-return-statement-insert-int[^]
Your GetInsertStatmentText method is useless. You can't execute the string that's returned, because you need the parameters as well.

Create a method to generate and return a SqlCommand object to insert a single item from your JSON file:
C#
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;
}
Then generate and execute the insert commands for the tokens you want to process. You'll want to do this within a transaction - either all tokens are inserted, or none of them are.
C#
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();
        }
    }
}
 
Share this answer
 
Comments
ahmed_sa 18-Aug-19 23:24pm    
Thank you very much for help and support when i execute it
No mapping exists from object type Newtonsoft.Json.Linq.JValue to a known managed provider native type
so that how to solve that error please ?
Richard Deeming 19-Aug-19 14:20pm    
That's a problem with the GetSqlParams method. Try changing it to:
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;
}
The important part is replacing jt.First with jt.First.ToObject<JValue>().Value.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900