ASP.Net : DataTable convert to JSON with Hierarchy - c#

Hi I'm having a problem in converting my dataTable to JSON format but i cannot get the output that i want.
Here is the example of the datatable
Parent Child
P1 c1
P1 c2
P1 c3
P2 c4
the output that I need is:
[{
Parent:P1,
Child:[
{c1},
{c2},
{c3}
]
},
{
Parent:P2
Child:[{c4}]
}]
But the Output that i always get is:
[{Parent:P1, Child:c1}, {Parent:P1, Child:c2}, {Parent:P1, Child:c3}, {Parent:P2,
Child:c4}]

Use this following code to get your desired result.
public class ParentNode
{
public ParentNode()
{
this.Child = new List<ChildNode>();
}
public string Parent { get; set; }
public List<ChildNode> Child { get; set; }
}
public class ChildNode
{
public string Child { get; set; }
}
class DataTableTOJSON
{
public static string GetJSON(DataTable dt)
{
List<ParentNode> parent = new List<ParentNode>();
for (int i = 0; i < dt.Rows.Count; i++)
{
var innerRow = dt.Rows[i]["Parent"];
var objParent = new ParentNode();
bool alreadyExists = parent.Any(x => x.Parent.Contains(innerRow.ToString()));
if (alreadyExists)
continue;
DataRow[] foundRows = dt.Select("[Parent]='" + innerRow + "'");
for (int k = 0; k < foundRows.Count(); k++)
{
var objChild = new ChildNode();
objChild.Child = foundRows[k]["Child"].ToString();
objParent.Child.Add(objChild);
}
objParent.Parent = innerRow.ToString();
parent.Add(objParent);
}
JavaScriptSerializer jsonString = new JavaScriptSerializer();
return jsonString.Serialize(parent);
}
}
Your will get the following output.
[{"Parent":"P1","Child":[{"Child":"c1"},{"Child":"c2"},{"Child":"c3"}]},{"Parent":"P2","Child":[{"Child":"c4"}]}]
I hope this will help you.

Related

read from csv to object[] C#

I am trying to read from a .csv file to an object array.
There are other solutions here that give solutions for lists but I cannot seem to make it work for me.
Object definition:
public class DTOClass
{
//declare data members
[DataMember]
public DateTime Date { get; set; }
[DataMember]
public string stock_symbol { get; set; }
[DataMember]
public double stock_price_open { get; set; }
[DataMember]
public double stock_price_close { get; set; }
[DataMember]
public double stock_price_low { get; set; }
[DataMember]
public double stock_price_high { get; set; }
[DataMember]
public double stock_price_adj_close { get; set; }
[DataMember]
public long stock_volume { get; set; }
[DataMember]
public string stock_exchange { get; set; }
}
Instance declaration:
private DTOClass[] _dTOs;
Filter method:
private List<DTOClass> FromCsv(string csvLine, List<DTOClass> rest)
{
DataTable _dt = new DataTable();
string[] values = csvLine.Split(',');
int j = _dt.Rows.Count;
for (int i = 0; i < j; i++)
{
DTOClass dto = new DTOClass();
dto.Date = Convert.ToDateTime(values[0]);
dto.stock_symbol = Convert.ToString(values[1]);
dto.stock_price_open = Convert.ToDouble(values[2]);
dto.stock_price_close = Convert.ToDouble(values[3]);
dto.stock_price_low = Convert.ToDouble(values[4]);
dto.stock_price_high = Convert.ToDouble(values[5]);
dto.stock_price_adj_close = Convert.ToDouble(values[6]);
dto.stock_volume = Convert.ToInt64(values[7]);
dto.stock_exchange = Convert.ToString(values[8]);
rest.Add(dto);
}
return rest;
}
Calling filter:
DTO = File.OpenText(Filename).ReadLine().Select(v => FromCsv(v.ToString(),
_restDto)).ToArray();
I need this to return to an object array because it then goes into a CollectionView on a datagrid.
But I keep getting this error:
"Cannot implicitly convert type 'System.Collections.Generic.List[]' to 'MBM.Services.DTOClass[]'"
I know that I'm obviously returning a list of a list, but I've tried other methods that are offered and I'm simply stumped.
I've also tried this:
private static DataTable GetDataTableFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
//csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return csvData;
}
Calling with:
DataTable csvData = GetDataTableFromCSVFile(Filename);
But this doesn't seem to return anything from the file.
Any help is appreciated, thanks.
One simple way will be to split the lines and select them into your new object.
var result = File.ReadAllLines("pathTo.csv")
.Select(line => line.Split(','))
.Select(x => new MyObject {
prop1 = x[0],
prop2 = x[1],
//etc..
})
.ToArray();
There's no point in recreating the wheel, Id just use CsvHelper, it has support for what you're doing in addition to handling malformed CSV's you can additionally set up mapping like so:
public sealed class MyClassMap : ClassMap<MyClass>
{
public MyClassMap()
{
AutoMap();
Map( m => m.CreatedDate ).Ignore();
}
}
Then you can get the object like so:
var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();

Bind a linkedlist to a datagridview

I'm trying to bind a linkedlist to a datagridview. The method below works for the properties in the class except the array.
If I declare the array as a new instance the linkedlist is created correctly, but the array is not bound into the datagridview.
If the array is created as a property (I think the code is correct) causes An unhandled exception of type 'System.StackOverflowException' occurred when the linkedlist is created.
Thanks for any help.
public class PayoffNode
{
public int DealNo { get; set; }
public string Category { get; set; }
public string Strategy { get; set; }
public string GreekType { get; set; }
// declare array as instance or as a property?
//public double[] Data = new double[22];
public double[] Data
{
get { return Data; }
set { Data = value; }
}
}
LinkedList<Globals.PayoffNode> PayLL = new LinkedList<Globals.PayoffNode>();
Random Rnd = new Random();
for (int K = 1; K <= 10; K++)
{
var T = new Globals.PayoffNode();
T.Category = "Account==" + K;
T.GreekType = "Greek==" + K;
T.DealNo = K;
T.Strategy = "Strategy==" + K;
for (int DP = 1; DP <= 21; DP++)
{
T.Data[DP] = Rnd.Next(10, 99);
}
PayLL.AddLast(T);
}
List<Globals.PayoffNode> qP = (from P in PayLL
where P.Category == "Account==4" && P.DealNo == 4 && P.GreekType == "Greek==4" && P.Strategy == "Strategy==4"
select P).ToList();
PayoffTable.DataSource = qP;
Update:
Thanks for the comments, this seems to be working.
public class PayoffNode
{
public int DealNo { get; set; }
public string Category { get; set; }
public string Strategy { get; set; }
public string GreekType { get; set; }
public double Data1 { get; set; }
public double Data2 { get; set; }
public double Data3 { get; set; }
public double[] Data = new double[22];
}
LinkedList<Globals.PayoffNode> PayLL = new LinkedList<Globals.PayoffNode>();
Random Rnd = new Random();
for (int K = 1; K <= 10; K++)
{
var T = new Globals.PayoffNode();
T.Category = "Account==" + K;
T.GreekType = "Greek==" + K;
T.DealNo = K;
T.Strategy = "Strategy==" + K;
for (int DP = 1; DP <= 21; DP++)
{
T.Data[DP] = Rnd.Next(10, 99);
}
PayLL.AddLast(T);
}
List<Globals.PayoffNode> qP = (from P in PayLL
where P.Category == "Account==4" && P.DealNo == 4 && P.GreekType == "Greek==4" && P.Strategy == "Strategy==4"
select new Globals.PayoffNode()
{
Category=P.Category,
DealNo=P.DealNo,
GreekType=P.GreekType,
Strategy=P.Strategy,
Data1=P.Data[1],
Data2 = P.Data[2],
Data3 = P.Data[3],
}).ToList();
PayoffTable.DataSource = qP;
One way to avoid making 21 Data properties is to convert the List to DataTable:
class PayoffNode
{
public int DealNo;
public string Category;
public double[] Data; // = new double[21];
}
and then
Random Rnd = new Random();
List<PayoffNode> PayLL = Enumerable.Range(1, 10).Select(i => new PayoffNode {
DealNo = i,
Category = "Account==" + i,
Data = Enumerable.Range(1, 21).Select(d => (double)Rnd.Next(10, 99)).ToArray()
}).ToList();
// List<PayoffNode> to DataTable
var dt = new DataTable();
dt.Columns.Add("DealNo", typeof(int));
dt.Columns.Add("Category"); // typeof(string) by default
for (int i = 1; i <= 21; i++)
dt.Columns.Add("Data" + i, typeof(double));
foreach (var P in PayLL)
{
var dr = dt.Rows.Add(P.DealNo, P.Category);
for (int i = 0; i < 21; i++)
dr[i+2] = P.Data[i]; // +2 is the number of fields before the Data fields
}
PayoffTable.DataSource = dt;
dt.DefaultView.RowFilter = " Category = 'Account==4' ";
The advantage is that you set the DataSource only once and just change the RowFilter to filter it. Also, any changes made in the DataGridView change the DataTable and vice-versa.
Note that arrays in C# and most other languages start from 0 and not from 1 ( .Data[0] to access the first item in the array ), so the for loop to access the Data array in my example is from 0 to 20.
public double[] Data
{
get { return Data; }
set { Data = value; }
}
This is the problem, the object in the set and get method needs to refer to a different object otherwise whenever the object value is set or trying to be retrieved it will just keep calling these methods infinitely. should be...
private double[] _data;
public double[] Data
{
get { return _data; }
set { _data = value; }
}
or...
public double[] Data { get; set; }

How to traverse a N ary tree

I have some working code with the help of others which creates a 3 deep N ary tree (or just 3 linked nodes), but I don't know how to traverse the list of nodes to find data - for example the trip distance for CarNo=6, Driver=Thor4 and TripNo=38. Sorry if this is trivial, I'm new to data structures and extensive net searches hasn't helped. Thanks for any help.
public class Node
{
public List<Node> Children = new List<Node>();
public Node Parent = null;
public Node(Node fromParent = null)
{
if (fromParent != null)
{
Parent = fromParent;
fromParent.Children.Add(this);
}
}
}
public class Root : Node
{
public int PoolNo;
public int CarNo;
string Make;
public Root(int _PoolNo, int _CarNo, string _Make) : base(null)
{
PoolNo = _PoolNo;
CarNo = _CarNo;
Make = _Make;
}
}
public class Parameter : Node
{
public string Driver;
public Parameter(string _Driver, Node fromParent = null) : base(fromParent)
{
Driver = _Driver;
}
}
public class Value : Node
{
public int TripDistance;
public int TripNo;
public Value(int _TripDistance, int _TripNo, Node fromParent = null) : base(fromParent)
{
TripDistance = _TripDistance;
TripNo = _TripNo;
}
}
List<Node> CarPool = new List<Node>();
public void IDTree()
{
Random Rnd = new Random();
for (int K = 1; K <= 20; K++)
{
var Car = new Root(6,K, "Ford" + K); // PoolNo,CarNo,Make
for (int KK = 1; KK <= 30; KK++)
{
var Driver = new Parameter("Thor" + KK, Car); // Driver
for (int KKK = 1; KKK <= 58; KKK++)
{
int Distance = Rnd.Next(1, 1000);
var Details = new Value(Distance, KKK, Driver); // TripDistance,TripNo
}
}
CarPool.Add(Car);
}
// traverse CarPool list to find trip distance for Carno 6, driver Thor4, tripno 38
foreach(var T in CarPool)
{
// not sure how to do this...
}
}

How to transform list of hierarchyid into a binary tree

I am working on a multi-level marketing (binary) which looks like this:
(but the binary tree is not required to be perfect. A node can have 0-2 child)
My problem is the data that I fetch from the database is flat list.
Notice that I am using hierarchyid (sql server 2014)
Basically the TextNode column is like a breadcrumb.
every slash / represents a level.
If I have TextNode of /1/ as root. then every node that starts with /1/ belongs to that root which are /1/, /1/1/ and /1/1/1/ (the root node is included which will be the level 0)
I've tried the accepted answer in this question but its not working.
How can I transform the flatlist to a Binary Tree so that I can easily traverse and display it on a screen?
Im using C#, ASP MVC 5, SQL Server 2014 if it matters.
I implement exactly this code According to Alex implementation but as is mentioned in some case it didn't work correctly .. have a look to my Image and my code (which copied from Alex post) [data in the database are correct but in tree view seems some problems ]
public class Row : IRow<string>
{
public string TextNode { get; }
public string Value { get; }
public long Id { get; }
public string FIN { get; }
public Row(string textNode, string userName, long id, string fin)
{
FIN = fin;
Id = id;
TextNode = textNode;
Value = userName;
}
}
public interface IRow<out T>
{
string TextNode { get; }
long Id { get; }
string FIN { get; }
T Value { get; }
}
public class TreeNode<T>
{
private struct NodeDescriptor
{
public int Level { get; }
public int ParentIndex { get; }
public NodeDescriptor(IRow<T> row)
{
var split = row.TextNode.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
Level = split.Length;
ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
}
}
public T title { get; }
public long Id { get; }
public string FIN { get; }
public List<TreeNode<T>> children { get; }
private TreeNode(T value, long id, string fin)
{
Id = id;
FIN = fin;
title = value;
children = new List<TreeNode<T>>();
}
public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
{
if (rows.Count == 0)
return null;
var result = new TreeNode<T>(rows[0].Value, rows[0].Id, rows[0].FIN);
FillParents(new[] { result }, rows, 1, 1);
return result;
}
private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
{
var result = new List<TreeNode<T>>();
for (int i = index; i < rows.Count; i++)
{
var descriptor = new NodeDescriptor(rows[i]);
if (descriptor.Level != currentLevel)
{
FillParents(result, rows, i, descriptor.Level);
return;
}
var treeNode = new TreeNode<T>(rows[i].Value, rows[i].Id, rows[i].FIN);
parents[descriptor.ParentIndex].children.Add(treeNode);
result.Add(treeNode);
}
}
}
g
this is also my JSON output for more information :
{"title":"Earth","Id":32,"FIN":"FIN","children":[{"title":"Europe","Id":33,"FIN":"FIN001","children":[{"title":"France","Id":35,"FIN":"FIN001001","children":[{"title":"Paris","Id":36,"FIN":"FIN001001001","children":[]},{"title":"Brasilia","Id":41,"FIN":"FIN002001001","children":[]},{"title":"Bahia","Id":42,"FIN":"FIN002001002","children":[]}]},{"title":"Spain","Id":38,"FIN":"FIN001002","children":[{"title":"Madrid","Id":37,"FIN":"FIN001002001","children":[{"title":"Salvador","Id":43,"FIN":"FIN002001002001","children":[]}]}]},{"title":"Italy","Id":45,"FIN":"FIN001003","children":[]},{"title":"Germany","Id":48,"FIN":"FIN001004","children":[]},{"title":"test","Id":10049,"FIN":"FIN001005","children":[]}]},{"title":"South America","Id":34,"FIN":"FIN002","children":[{"title":"Brazil","Id":40,"FIN":"FIN002001","children":[{"title":"Morano","Id":47,"FIN":"FIN001003001","children":[]}]}]},{"title":"Antarctica","Id":39,"FIN":"FIN003","children":[{"title":"McMurdo Station","Id":44,"FIN":"FIN003001","children":[]}]}]}
Here is a very simple implementation (assuming that Nodes are in the right order), which may be enhanced in multiple ways
public interface IRow<out T>
{
string TextNode { get; }
T Value { get; }
}
public class TreeNode<T>
{
private struct NodeDescriptor
{
public int Level { get; }
public int ParentIndex { get; }
public NodeDescriptor(IRow<T> row)
{
var split = row.TextNode.Split(new [] {"/"}, StringSplitOptions.RemoveEmptyEntries);
Level = split.Length;
ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
}
}
public T Value { get; }
public List<TreeNode<T>> Descendants { get; }
private TreeNode(T value)
{
Value = value;
Descendants = new List<TreeNode<T>>();
}
public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
{
if (rows.Count == 0)
return null;
var result = new TreeNode<T>(rows[0].Value);
FillParents(new[] {result}, rows, 1, 1);
return result;
}
private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
{
var result = new List<TreeNode<T>>();
for (int i = index; i < rows.Count; i++)
{
var descriptor = new NodeDescriptor(rows[i]);
if (descriptor.Level != currentLevel)
{
FillParents(result, rows, i, descriptor.Level);
return;
}
var treeNode = new TreeNode<T>(rows[i].Value);
parents[descriptor.ParentIndex].Descendants.Add(treeNode);
result.Add(treeNode);
}
}
}
Sample usage:
public class Row : IRow<string>
{
public string TextNode { get; }
public string Value { get; }
public Row(string textNode, string userName)
{
TextNode = textNode;
Value = userName;
}
}
class Program
{
static void Main(string[] args)
{
IRow<string>[] rows =
{
new Row("/", "Ahmed"),
new Row("/1/", "Saeed"),
new Row("/2/", "Amjid"),
new Row("/1/1/", "Noura"),
new Row("/2/1/", "Noura01"),
new Row("/2/2/", "Reem01"),
new Row("/1/1/1", "Under_noura")
};
var tree = TreeNode<string>.Parse(rows);
PrintTree(tree);
}
private static void PrintTree<T>(TreeNode<T> tree, int level = 0)
{
string prefix = new string('-', level*2);
Console.WriteLine("{0}{1}", prefix, tree.Value);
foreach (var node in tree.Descendants)
{
PrintTree(node, level + 1);
}
}
}

list class property in a class c# assign value

class Program
{
static void Main(string[] args)
{
Posting onjPosting = null;
List<Posting> objList = null;
for (int i = 0; i < 100; i++)
{
onjPosting = new Posting();
onjPosting.Key1 = i;
for (int j = 0; j < 5; i++)
{
Choice objChoice = new Choice();
objChoice.ID = i;
objChoice.VAL = j;
onjPosting.GetPostingChoice.Add(objChoice); // GETTING ERROR [ Object reference not set to an instance of an object. ]
}
objList.Add(onjPosting);
}
}
}
public class Choice
{
public int ID { get; set; }
public int VAL { get; set; }
}
public class Posting
{
public int Key1 { get; set; }
public List<Choice> GetPostingChoice { get; set; }
}
While looping through and assigning the value I am getting error . How to solve this ? Please help me out .
My requirement is one parent class (Posting) , can contain number of data List .
Thanks in advance .
You never allocate the GetPostingChoice list so of course it is null.
You could do it in the constructor:
public class Posting
{
public Posting()
{
GetPostingChoice = new List<Choice>();
}
public int Key1 { get; set; }
public List<Choice> GetPostingChoice { get; set; }
}
Add a public constructor on your Posting class:
public class Posting
{
public int Key1 { get; set; }
public List<Choice> GetPostingChoice { get; set; }
public Posting()
{
GetPostingChoice = new List<Choice>();
}
}
You also have other errors:
You do not initialize objList, so you cannot add in there.
List<Posting> objList = null;
So you will get another Null Reference when you get to:
List<Posting> objList = null;
In your second loop you increase i instead of j so it will never end.
for (int j = 0; j < 5; i++)
This is how it should look:
Posting onjPosting = null;
List<Posting> objList = new List<Posting>();
for (int i = 0; i < 1; i++)
{
onjPosting = new Posting();
onjPosting.Key1 = i;
for (int j = 0; j < 5; j++)
{
Choice objChoice = new Choice();
objChoice.ID = i;
objChoice.VAL = j;
onjPosting.GetPostingChoice.Add(objChoice); // GETTING ERROR [ Object reference not set to an instance of an object. ]
}
objList.Add(onjPosting);
}
Since you ask for another approach, and this is just one of the many ways you could do it, have a look at this:
List<Posting> objList = new List<Posting>();
Enumerable.Range(0,100)
.Select
(
(x,i)=>new Posting
{
Key1 = i,
GetPostingChoice = Enumerable.Range(0,5).Select((p,j)=>new Choice{ID = i,VAL = j}).ToList()
}
);

Categories