Converting Excel to JSON using c# dictionary - c#

I am using this code to convert an Excel file into a JSON format.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var pathToExcel = #"D:\works\sample.xlsx";
var sheetName = "sa";
var connectionString = String.Format(#"
Provider=Microsoft.ACE.OLEDB.12.0;
Data Source={0};
Extended Properties=""Excel 12.0 Xml;HDR=YES""
", pathToExcel);
using (var conn = new OleDbConnection(connectionString))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = String.Format(
#"SELECT * FROM [{0}$]",
sheetName
);
using (var rdr = cmd.ExecuteReader())
{
var query =
(from DbDataRecord row in rdr
select row).Select(x =>
{
Dictionary<string, object> item = new
Dictionary<string, object>();
for(int i=0;i<20;i++)
{
item.Add(rdr.GetName(i), x[i]);
}
return item;
});
//Generates JSON from the LINQ query
var json = JsonConvert.SerializeObject(query);
var result = json;
Console.WriteLine(result);
//return json;
}
}
}
}
}
The requirement is that I need to create sub serialized object within the JSON. For example, if a cell has a value:
"name": "abc,def", the output must be:
"name":
{
"name1": "abc",
"name2": "def"
}
How can I modify my code to achieve this?

try this code this will help you i hope
//dynamic item = new ExpandoObject();
Dictionary<string, object> item = new Dictionary<string, object>();
for(int i=0;i<20;i++)
{
if(x[i].ToString().Contains(","))
{
Dictionary<string, object> temp = new Dictionary<string, object>()
string[] data = x[i].ToString().Split(',');
for(int j=0;j<data.Length;j++)
{
temp.Add(rdr.GetName(i)+j, data[j]);
}
item.Add(rdr.GetName(i), temp);
}
else
{
item.Add(rdr.GetName(i), x[i]);
Console.WriteLine("\n");
}
}

Related

C#: Sorting a dictionary in which the keys are List<object>

Hello to everyone reading this! Tl;dr I have a Dictionary<string, List<object>> called
"table" with the following keys:
"id" being int,
"date" being Datetime,
"name", "entry1", "entry2", "entry3" being strings.
And all the values to the keys in the List<object> list. I want to order the dictionary by the name field, the names being like "John Doe". I tried using .OrderBy() and it would either throw exceptions or order just that key and not the whole dictionary. Ex: var result = table.Orderby(pairs => pairs.Value[2]); would throw an exception because the object is not a string.
How can this be done? Thank you!
Edit:
The table is used to use the values in an Excel file:
foreach (var key in table.Keys)
{
for (int i = 0; i < max; i++)
{
switch (key)
{
case "id":
worksheet.Cells[i + 1, j].Value = ConversionWrapper<int>((int)table[key][i]);
break;
case "date":
worksheet.Cells[i + 1, j].Value = ConversionWrapper<string>((DateTime)table[key][i]);
break;
case "name":
case "entry1":
case "entry2":
case "entry3":
case "entry4":
worksheet.Cells[i + 1, j].Value = ConversionWrapper<string>((string)table[key][i]);
break;
default:
break;
}
}
++j;
}
private static T ConversionWrapper<T>(object elem)
{
switch (elem)
{
case int:
case string:
return (T)elem;
case DateTime:
return (T)(object)((DateTime)elem).ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
default:
throw new ArgumentException();
}
}
Method to extract the values:
private static Dictionary<string, List<object>> GetAllElementsLM(SqlConnection conn)
{
string query;
string[] columns = { "id", "date", "name", "entry1", "entry2", "entry3", "entry4" };
var dic = new Dictionary<string, List<object>>();
conn.Open();
foreach (var elem in columns)
{
dic.Add(elem, new List<object>());
query = $#"SELECT {elem} FROM ""feedback""";
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
dic[elem].Add(reader.GetValue(0));
}
}
}
}
conn.Close();
return dic;
}
The class you want to sort on (the list in this case) needs to implement the IComparer interface. Then the OrderBy operator calls IComparer.Compare to determine the sort sequence.
IComparer.Compare
So you need to create a class that extends List and implements IComparer. Inside this class' Compare method you can do whatever is necessary to determine which list is greater (based on some value within the list for example). Your dictionary will then take this new class as the second type.
Ended up using a List of my structure:
Entries structure:
readonly struct Entries
{
public int Id { get; }
public DateTime Date { get; }
public string Name { get; }
public string Entry1 { get; }
public string Entry2 { get; }
public string Entry3 { get; }
public string Entry4 { get; }
public Entries(int id, DateTime date, string name, string entry1, string entry2, string entry3, string entry4) =>
(Id, Date, Name, Entry1, Entry2, Entry3, Entry4) = (id, date, name, entry1, entry2, entry3, entry4);
}
Method to get the number of elements:
private static int GetMaxNumber(SqlConnection conn)
{
int i = 0;
string query;
conn.Open();
query = $#"SELECT id FROM ""feedback""";
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
++i;
}
}
}
conn.Close();
return i;
}
Getting the elements:
private static IEnumerable<Entries> GetAllElementsClass(SqlConnection conn)
{
string query;
List<int> id;
List<DateTime> date;
List<string> name, entry1, entry2, entry3, entry4;
int max = GetMaxNumber(conn);
conn.Open();
query = $#"SELECT id FROM ""feedback""";
id = new List<int>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
id.Add((int)reader.GetValue(0));
}
}
}
query = $#"SELECT date FROM ""feedback""";
date = new List<DateTime>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
date.Add((DateTime)reader.GetValue(0));
}
}
}
query = $#"SELECT name FROM ""feedback""";
name = new List<string>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
name.Add((string)reader.GetValue(0));
}
}
}
query = $#"SELECT entry1 FROM ""feedback""";
entry1 = new List<string>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
entry1.Add((string)reader.GetValue(0));
}
}
}
query = $#"SELECT entry2 FROM ""feedback""";
entry2 = new List<string>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
entry2.Add((string)reader.GetValue(0));
}
}
}
query = $#"SELECT entry3 FROM ""feedback""";
entry3 = new List<string>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
entry3.Add((string)reader.GetValue(0));
}
}
}
query = $#"SELECT entry4 FROM ""feedback""";
entry4 = new List<string>();
using (var command = new SqlCommand(query, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
entry4.Add((string)reader.GetValue(0));
}
}
}
for (int i = 0; i < max; i++)
{
yield return new Entries(id[i], date[i], name[i], entry1[i], entry2[i], entry3[i], entry4[i]);
}
conn.Close();
}
Sorting them:
private static List<Entries> SortEntries(SqlConnection conn)
{
var entries = new List<Entries>();
foreach (var element in GetAllElementsClass(conn))
{
entries.Add(element);
}
entries = entries.OrderBy(x => x.Name).ToList();
return entries;
}

c# using JavaScriptSerializer serializer in while loop and returning to client side to Json.Parse. Getting a error

Could anyone give me a step to solve this error in getting a output. New to coding.
Step 1:
Using Json/Javascript calling a method which is in .cs file(c#)
var markers = JSON.parse('<%=ConvertDataTabletoString("NewGetTaskWorkPercentage1",null) %>');
Step 2:
.cs file code for method ConvertDataTabletoString
public string ConvertDataTabletoString(string Sql, string prjno)
{
//var qprojectno = Request.QueryString["ProjectNo"].ToString();
param1.Value = "P-2020-0009"; //aspx hidden field
DataTable dt = new DataTable();
using (con = new SqlConnection(connectionString))
{
using (cmd = new SqlCommand(Sql, con))
{
string connetionString = "Data Source = ; Initial Catalog = DashBoardDB; User ID = ; Password = ";
SqlConnection connection = new SqlConnection(connetionString);
connection.Open();
string sql1 = "SELECT InstanceId,Module,SubModule,Process FROM Xtable WHERE ProjectNo=" + "'" + param1.Value + "'"+ "and instanceid='aabed4df-3e91-41c0-8788-2e7d31eecfd8'";
SqlCommand command = new SqlCommand(sql1, connection);
command.CommandTimeout = 600;
SqlDataReader dataReader = command.ExecuteReader();
serializedResult = " ";
while (dataReader.Read())
{
string strInsId = " ";
string strProcess = "";
strInsId = dataReader["InstanceId"].ToString();
con.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("#ProjectNo", prjno));
cmd.Parameters.Add(new SqlParameter("#InstanceId", strInsId));
sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> row;
foreach (DataRow dr in dt.Rows)
{
Console.WriteLine(dr + " " + dt.Rows);
row = new Dictionary<string, object>();
foreach (DataColumn col in dt.Columns)
{
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
serializedResult = serializer.Serialize(rows);
serializedResult += serializer.Serialize(rows); **two times concatenating**
con.Close();}
dataReader.Close();
command.Dispose();
connection.Close();
return serializedResult;
}
}
}
Step 3:
Image Attached
In client side how to split this values into arrays. I required output like this. How can i get the output in array and the length of the array at client side. Thanks
Array 1:
[{"Task":"Feature 1.1.3","OverallSubtaskDuration":17.00,"ActualStart":"2019/10/18","ActualEnd":"2020/03/13","OverallSubtaskPercentage":283.33},
{"Task":"Feature 1.1.3","OverallSubtaskDuration":8.00,"ActualStart":"2019/10/18","ActualEnd":"2019/10/25","OverallSubtaskPercentage":133.33},
{"Task":"Feature 1.1.3","OverallSubtaskDuration":3.00,"ActualStart":"2020/03/11","ActualEnd":"2020/03/13","OverallSubtaskPercentage":50.00},
{"Task":"Feature 1.1.3","OverallSubtaskDuration":3.00,"ActualStart":"2019/10/27","ActualEnd":"2019/10/29","OverallSubtaskPercentage":50.00}]
Array 2:
[{"Task":"Feature 1.1.3","OverallSubtaskDuration":17.00,"ActualStart":"2019/10/18","ActualEnd":"2020/03/13","OverallSubtaskPercentage":283.33},
{"Task":"Feature 1.1.3","OverallSubtaskDuration":8.00,"ActualStart":"2019/10/18","ActualEnd":"2019/10/25","OverallSubtaskPercentage":133.33},
{"Task":"Feature 1.1.3","OverallSubtaskDuration":3.00,"ActualStart":"2020/03/11","ActualEnd":"2020/03/13","OverallSubtaskPercentage":50.00},
{"Task":"Feature 1.1.3","OverallSubtaskDuration":3.00,"ActualStart":"2019/10/27","ActualEnd":"2019/10/29","OverallSubtaskPercentage":50.00}]
The JSON result has to be either an object or an array.
The result you are creating is two arrays back to back and therefore not valid JSON and you can test this by using an online validator such as https://jsonlint.com/
So you either need to create one large array with all the elements from both your other arrays, or you need to wrap the two arrays into a wrapper object.
The simplest for you, as you have already are using a List<>, is to combine this with itself and return the result.
//Add the "rows" list to itself, so you double it.
rows.AddRange(rows);
serializedResult = serializer.Serialize(rows);
...
return serializedResult;
If you need to keep the lists distinct then you have to use a wrapper object. Like this;
public class Wrapper
{
public List<Dictionary<string, object>> Array1 { get; set; }
public List<Dictionary<string, object>> Array2 { get; set; }
}
Then you serialise like this
serializedResult = serializer.Serialize(new Wrapper() { Array1 = rows, Array2 = rows };);
...
return serializedResult;
You can use newtonsoft json dll to create json file from .cs, and check json string with link: https://jsoneditoronline.org/

Read data from SQL Server with dictionary in C#

var query = "SELECT OrderNo, PlannedQuantity, CompletedQuantity, IsClosed" +
" FROM Order1 WHERE OrderNo =:orderNo";
var arguments = new Dictionary<string, object>() { { "orderNo", orderNo } };
using (var reader = ExecuteDatabaseReader(query, arguments))
{
if (reader.Read())
{
return GetOrderFromReader(reader);
}
}
static IDataReader ExecuteDatabaseReader(string query, IDictionary<string, object> arguments)
{
return null;
}
You should implement a method like below. Of cource code below is a simple code and it needs to be very better. For example, I haven't managed to close and dispose the connection.
static IDataReader ExecuteDatabaseReader(string query, IDictionary < string, object > arguments) {
var conn = new SqlConnection(your_connection_string);
conn.Open();
var commadn = conn.CreateCommand();
command.CommandText = query;
foreach(var key in arguments.Keys) {
command.Parameters.AddWithValue(key, arguments[key]);
}
return command.ExecuteReader();
}
One important notes about parameters, I don't know what your RDBMS is if it's SQL Server you need to define your parameters with # sign.
var dictionary = new Dictionary<string, object>();
dictionary.Add("#Id", 1);
dictionary.Add("#Name", "Name");

Retrieving data from a database through SqlDataReader and converting it to JSON

I want to convert my retrieved data into JSON; I am using a SqlDataReader for retrieving. For that I need to store my data into var.
I am getting this error:
An exception of type 'System.Reflection.AmbiguousMatchException' occurred in mscorlib.dll but was not handled in user code
Additional information: Ambiguous match found.
in the following code:
public string GetDetails(int Id)
{
var jsonDoc = "";
string con = "server=FACULTY01\\SQLSERVER2012ENT; database=SampleDb; uid=sa; pwd=sa9";
SqlConnection scon = new SqlConnection(con);
string qry = "Select * from Information where ID =" + Id;
SqlCommand cmd = new SqlCommand(qry, scon);
scon.Open();
SqlDataReader rdr = cmd.ExecuteReader();
var details = rdr;
JavaScriptSerializer jss = new JavaScriptSerializer();
jsonDoc = jss.Serialize(details);
scon.Close();
return jsonDoc;
}
You can't directly serialize a SqlDataReader and expect the output to contain the data from the SQL query. That's not the way that SqlDataReader works. SqlDataReader is a means to retrieve data from the SQL result. You can use it to populate some other object (such as a Dictionary<string, object> or a strongly-typed class you define) which you can then hand to the serializer to produce JSON.
Try the code below instead. (Also note the use of using statements and parameterized SQL in keeping with good coding practices, as mentioned by #Jon Skeet.)
public static string GetDetails(int Id)
{
string con = "server=FACULTY01\\SQLSERVER2012ENT; database=SampleDb; uid=sa; pwd=sa9";
using (SqlConnection scon = new SqlConnection(con))
{
string qry = "Select * from Information where ID = #id";
SqlCommand cmd = new SqlCommand(qry, scon);
cmd.Parameters.AddWithValue("#id", Id);
scon.Open();
var details = new Dictionary<string, object>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr.HasRows && rdr.Read())
{
for (int i = 0; i < rdr.FieldCount; i++)
{
details.Add(rdr.GetName(i), rdr.IsDBNull(i) ? null : rdr.GetValue(i));
}
}
}
JavaScriptSerializer jss = new JavaScriptSerializer();
string jsonDoc = jss.Serialize(details);
scon.Close();
return jsonDoc;
}
}
Note that the above code is expecting to get a single row back from the reader. If you are expecting more than one row then you will need to use another loop and put the resulting data into a List<Dictionary<string, object>> instead. Here is the part you would need to change:
...
var details = new List<Dictionary<string, object>>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
while (rdr.Read())
{
var dict = new Dictionary<string, object>();
for (int i = 0; i < rdr.FieldCount; i++)
{
dict.Add(rdr.GetName(i), rdr.IsDBNull(i) ? null : rdr.GetValue(i));
}
details.Add(dict);
}
}
}
...
You need a loop to store the data from the reader. Use a DataTable to store the full table. A single variable will store single column data.
while (rdr.Read())
{
var details = rdr["columnName"];
}
Encountered this post as it comes first in google search.
Have given an answer here (based on this):
The requirement is somewhat similar that is of converting sqldatareader result to a json string.
public static class MyExtensions
{
public async static Task<string> toJSON(this SqlDataReader reader)
{
var results = await reader.GetSerialized();
return JsonConvert.SerializeObject(results, Formatting.Indented);
}
public async static Task<IEnumerable<Dictionary<string, object>>> GetSerialized(this SqlDataReader reader)
{
var results = new List<Dictionary<string, object>>();
var cols = new List<string>();
for (var i = 0; i < reader.FieldCount; i++)
cols.Add(reader.GetName(i));
while (await reader.ReadAsync())
results.Add(SerializeRow(cols, reader));
return results;
}
private static Dictionary<string, object> SerializeRow(IEnumerable<string> cols,
SqlDataReader reader)
{
var result = new Dictionary<string, object>();
foreach (var col in cols)
result.Add(col, reader[col]);
return result;
}
}
Use As :
var result = await reader.GetSerialized(); //to get the result object
or
string strResult = await reader.toJSON(); //to get the result string

how to retrieve values by LINQ in asp.net?

I want to set value to a literal control using LINQ. I got the result from database in var by the following code:
var result=md.StoredProc_Name(id);
Now I want to assign particular columns value to a literal. As we can do simply in asp.net as bellow with the help of datatable,
dt=obj.Test(id);
ltrlName.Text=dt.Rows[0]["Name"].ToString();
ltrlAddress.Text=dt.Rows[0]["Address"].ToString();
How can we do the same thing in LINQ?
var first = result.FirstOrDefault();
if (first != null)
{
ltrlName.Text = first.Name;
ltrlAddress.Text = first.Address;
}
Addendum - How to do this without linq to objects:
With the code below in a class called DB
var result = DB.SelectIntoItem("StoredProc_Name",
connectionString,
System.Data.CommandType.StoredProcedure,
new { param1 = "val1" });
if (!reader.Empty)
{
ltrlName.Text=result.Name;
ltrlAddress.Text=result.Address;
}
etc.
Code
public static dynamic SelectIntoItem(string SQLselect, string connectionString, CommandType cType = CommandType.Text, object parms = null)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
dynamic result = new System.Dynamic.ExpandoObject();
cmd.CommandType = cType;
cmd.CommandText = SQLselect;
if (parms != null)
Addparms(cmd, parms);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read()) // read the first one to get the columns collection
{
var cols = reader.GetSchemaTable()
.Rows
.OfType<DataRow>()
.Select(r => r["ColumnName"]);
foreach (string col in cols)
{
((IDictionary<System.String, System.Object>)result)[col] = reader[col];
}
result.Empty = false;
if (reader.Read())
{
// error, what to do?
result.Error = true;
result.ErrorMessage = "More than one row in result set.";
}
else
{
result.Error = false;
}
}
else
{
result.Empty = true;
result.Error = false;
}
}
conn.Close();
return result;
}
}
}
private static void Addparms(SqlCommand cmd, object parms)
{
// parameter objects take the form new { propname : "value", ... }
foreach (PropertyInfo prop in parms.GetType().GetProperties())
{
cmd.Parameters.AddWithValue("#" + prop.Name, prop.GetValue(parms, null));
}
}
If you are insterested follow my GitHub, I'll be making the rest of it public soon (GitHub)

Categories