Nested Json String to DataTable - c#

I Need to convert the following Json string to DataTable.
{
"pnr":"1234567890",
"train_num":"12311",
"train_name":"HWH DLIKLK MAI",
"doj":"23-12-2013",
"from_station":
{
"code":"DLI",
"name":"Delhi"
},
"to_station":
{
"code":"KLK",
"name":"Kalka"
}
}
In DataTable I need to Display
train_num
train_name
doj
from_station(name only)
to_station(name only)
What i have till now is,
public class Train
{
public string train_num { get; set; }
public string train_name { get; set; }
public string doj { get; set; }
public from_station from_station { get; set; }
public to_station to_station { get; set; }
}
public class from_station
{
public string code { get; set; }
public string name { get; set; }
}
public class to_station
{
public string code { get; set; }
public string name { get; set; }
}
public static DataTable ToDataTable(Train data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(Train));
DataTable table = new DataTable();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(data);
}
table.Rows.Add(values);
return table;
}
var data = JsonConvert.DeserializeObject<Train>(JsonString);
dt = ToDataTable(data);
ui_grdVw_EmployeeDetail1.DataSource = dt;
ui_grdVw_EmployeeDetail1.DataBind();
I am getting only three columns in datatable
train_num
train_name
doj

You need to tweak your DataTable conversion method to be more Generic. Then pass for it the data shaped as you want it to be.
public static DataTable ToDataTable<T>( IList<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Note: the below method can be used to convert any List to DataTable.
Usage:
var data = JsonConvert.DeserializeObject<Train>(JsonString);
var shapedData = Enumerable.Range(0, 1).Select(x =>
new
{
train_num = data.train_num,
train_name = data.train_name,
doj = data.doj,
from_station = data.from_station.name,
to_station = data.to_station.name
}).ToList();
DataTable dt = ToDataTable(shapedData);

Related

How do I use reflection to dynamically call a type?

I have a DataGrid and I need to convert it to a DataTable. The problem is that I need To be able to get the type of my DataSource dynamically. The grid DataSource is of type 'Observable' which is a class I have in my project, but my task is to be able to dynamically create the DataTable without needing to specify the type only using the DataSource. How can I generate a method that I can use to place in <T> without getting the error " 'mytype' is a variable but is used like a type" .
Type mytype = Grid_Job.DataSource.GetType();
DataTable dt = CreateDataTable<mytype>((IEnumerable<mytype>)Grid_Job.DataSource);
public static DataTable CreateDataTable<T>(IEnumerable<T> list)
{
Type type = typeof(T);
var properties = type.GetProperties();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
foreach (T entity in list)
{
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
values[i] = properties[i].GetValue(entity);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
My Observable class is
public class Observable
{
public int JobNo { get; set; }
public string JobName { get; set; }
public string JobDescription { get; set; }
public string Job_Type { get; set; }
public string Job_Status { get; set; }
}
Effectively, you need to discard the generics and think in terms of the collection at runtime - discovering the element type itself. For example:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Reflection;
static class P
{
static object GetData()
=> new ObservableCollection<Observable>
{
new Observable { JobName = "abc", JobNo = 123 },
new Observable { JobName = "def", JobNo = 456 },
new Observable { JobName = "ghi", JobNo = 789 },
};
static void Main()
{
// note that we don't know *anything* about the data source here
object dataSource = GetData();
DataTable dt = CreateDataTable((IEnumerable)dataSource);
foreach (DataColumn col in dt.Columns)
{
Console.Write(col.ColumnName);
Console.Write("\t");
}
Console.WriteLine();
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
{
Console.Write(row[col]);
Console.Write("\t");
}
Console.WriteLine();
}
}
public static DataTable CreateDataTable(IEnumerable list)
{
Type type = GetElementType(list.GetType());
var properties = type.GetProperties();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
object[] values = new object[properties.Length];
foreach (object entity in list)
{
for (int i = 0; i < properties.Length; i++)
{
values[i] = properties[i].GetValue(entity);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
static Type GetElementType(Type type)
{
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition()
== typeof(IList<>))
{
return type.GetGenericArguments()[0];
}
}
return null;
}
}
public class Observable
{
public int JobNo { get; set; }
public string JobName { get; set; }
public string JobDescription { get; set; }
public string Job_Type { get; set; }
public string Job_Status { get; set; }
}
Note that in some cases you should prefer the TypeDescriptor model over reflection, as this allows runtime definition of properties; this is a niche area and probably doesn't apply to you, but it relevant to know about. As an example, this is how DataTable itself chooses to expose the properties it has as discoverable at runtime to general purpose tools. There are also a few list indirection APIs that need to be considered in those cases.

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>();

Convert the class as data table using extension method and lambda expression

I am trying to create a extension method to export the class as data-table, in this method I want to give facility to user to export the property with different name in datatable, suppose property name in class is "LoginName" but user want to export it as "Login" in data-table, also user can specify multiple properties to rename.
for example following is the class
public class UserInfo
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string LoginName { get; set; }
public int CompanyID { get; set; }
}
to export this class as data-table user will use extension method like this
UserInfo us = UserRep.GetUser("userID","Pass");
DataTable userDetails = null;
//Follwing is a pseudo code it could be different in possible manner
userDetails = us.ExportAsDataTable(u=> new {{u.LoginName,"Login"}, {u.CompanyID ,"Company"}});
//Or
userDetails = us.ExportAsDataTable(u=> new { Login = u.LoginName, Company = u.CompanyID});
following ExportAsDataTable metod I have created to do the functionality but unable to give correct expression to take the user input.
public static DataTable ExportAsDataTable<TSource, TProperty>(this TSource instance, Expression<Func<TSource, KeyValuePair<TProperty, string>>> renamePropertyMap)
{
DataTable dataTable = new DataTable();
//Doing export stuff here
return dataTable;
}
//Or
public static DataTable ConvertToDataTable<T>(this T instance, Expression<Func<T, object>> renamePropertyMap) where T : EntityBase
{
//Using this method I am able to get the new name of column from expression like this but not getting the original property name
string columnName = (renamePropertyMap.Body as NewExpression).Members[0].Name
/*note :- result in columnName is "Login" which is fine,
but I need to get orignal property name as well, that is
"LoginName", I am unable to get it from expression.*/
DataTable dataTable = new DataTable();
//Doing export stuff here
return dataTable;
}
I would do something like this instead:
public class FluentBuilder<T>
{
private readonly T _input;
private readonly Dictionary<string, string> _mappings = new Dictionary<string, string>();
public FluentBuilder(T input)
{
_input = input;
}
public FluentBuilder<T> Map(Expression<Func<T, object>> selector, string name)
{
MemberExpression member = selector.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", selector));
var propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", selector));
_mappings.Add(propInfo.Name, name);
return this;
}
private string GetName(PropertyInfo prop)
{
string map;
if (_mappings.TryGetValue(prop.Name, out map))
return map;
return prop.Name;
}
public DataTable ToDataTable(string tableName = null)
{
var result = new DataTable(tableName);
foreach (var prop in _input.GetType().GetProperties())
{
result.Columns.Add(GetName(prop));
}
var values = _input.GetType().GetProperties().Select(x => x.GetMethod.Invoke(_input, new object[0])).ToArray();
result.Rows.Add(values);
return result;
}
}
public static class FluentBuilderExtensions
{
public static FluentBuilder<T> SetupWith<T>(this T input)
{
return new FluentBuilder<T>(input);
}
}
class Program
{
public class UserInfo
{
public string MailAddress { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
static void Main(string[] args)
{
var userInfo = new UserInfo()
{
MailAddress = "foo#bar.com",
Username = "foouser",
Password = "barpassword"
};
var dt = userInfo.SetupWith()
.Map(x => x.MailAddress, "address")
.Map(x => x.Username, "user")
.ToDataTable();
}
}
MoreLINQ already provides ToDatatable() to convert an IEnumerable result to a DataTable. The method is available as part of the full NuGet package or as a source package that you can add to your project.
To generate a DataTable from a subset of UserInfo properties, use a Select before calling ToDataTable(), eg :
var table = myUserInfos.Select(us=>new {Login=us.LoginName, Company=us.CompanyID})
.ToDataTable();
If you only have one item and want to convert it to a single-row DataTable:
That's a very strange request. Why do you want to do that instead of eg binding the single object to the UI controls?
You can wrap it in an array eg:
var table = new[]{theUser}.Select(us=>new {Login=us.LoginName, Company=us.CompanyID})
.ToDataTable();
I used DataAnnotations and Reflection.
You need to add reference of missing libraries from following. I tested this code and it is working.
using System;
using System.Data;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var user = new UserInfo();
var name = GetAttributeFrom<DisplayAttribute>(user, "LoginName").Name;
var dt = objToDataTable(user);
Console.ReadLine();
}
public static DataTable objToDataTable(UserInfo obj)
{
DataTable dt = new DataTable();
UserInfo objU = new UserInfo();
foreach (PropertyInfo info in typeof(UserInfo).GetProperties())
{
dt.Columns.Add(GetAttributeFrom<DisplayAttribute>(objU, info.Name).Name);
}
dt.AcceptChanges();
return dt;
}
public static T GetAttributeFrom<T>(object instance, string propertyName) where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
return (T)property.GetCustomAttributes(attrType, false).First();
}
}
public class UserInfo
{
[Display(Name = "ID")]
public int UserID { get; set; }
[Display(Name = "FName")]
public string FirstName { get; set; }
[Display(Name = "LName")]
public string LastName { get; set; }
[Display(Name = "Login")]
public string LoginName { get; set; }
[Display(Name = "Company")]
public int CompanyID { get; set; }
}
This is how I build the extension method to convert the class as datatable
public static class EntityExtensions
{
private static readonly string expressionCannotBeNullMessage = "The expression cannot be null.";
private static readonly string invalidExpressionMessage = "Invalid expression.";
public static DataTable ConvertToDataTable<T>(this T instance, Expression<Func<T, object>> proprtiesToSkip = null, Expression<Func<T, object>> proprtiesToRename = null) where T : EntityBase
{
string columnName = "";
string orgPropName;
int counter = 0;
Dictionary<string, string> renameProperties = null;
MemberInfo newName = null;
NewExpression expression = null;
List<string> skipProps = null;
try
{
if (proprtiesToSkip != null )
{
if (proprtiesToSkip.Body is NewExpression)
{
skipProps = new List<string>();
expression = (proprtiesToSkip.Body as NewExpression);
foreach (var cExpression in expression.Arguments)
{
skipProps.Add(GetMemberName(cExpression));
}
}
else
{
throw new ArgumentException("Invalid expression supplied in proprtiesToSkip while converting class to datatable");
}
}
if (proprtiesToRename != null)
{
if (proprtiesToRename.Body is NewExpression)
{
renameProperties = new Dictionary<string, string>();
expression = (proprtiesToRename.Body as NewExpression);
foreach (var cExpression in expression.Arguments)
{
newName = expression.Members[counter];
orgPropName = GetMemberName(cExpression);
renameProperties.Add(orgPropName, newName.Name);
counter++;
}
}
else
{
throw new ArgumentException("Invalid expression supplied in proprtiesToRename while converting class to datatable");
}
}
var properties = instance.GetType().GetProperties().Where(o =>
{
return (skipProps != null && !skipProps.Contains(o.Name, StringComparer.OrdinalIgnoreCase) &&
(o.PropertyType != typeof(System.Data.DataTable) && o.PropertyType != typeof(System.Data.DataSet)));
}).ToArray();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
columnName = "";
if (renameProperties != null && renameProperties.ContainsKey(info.Name))
{
columnName = renameProperties[info.Name];
}
if (string.IsNullOrEmpty(columnName))
{
columnName = info.Name;
}
dataTable.Columns.Add(new DataColumn(columnName, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
values[i] = properties[i].GetValue(instance);
}
dataTable.Rows.Add(values);
return dataTable;
}
finally
{
renameProperties = null;
newName = null;
expression = null;
skipProps = null;
}
}
private static string GetMemberName(Expression expression)
{
if (expression == null)
{
throw new ArgumentException(expressionCannotBeNullMessage);
}
if (expression is MemberExpression)
{
// Reference type property or field
var memberExpression = (MemberExpression)expression;
return memberExpression.Member.Name;
}
throw new ArgumentException(invalidExpressionMessage);
}
}
Calling it like this
class Program
{
static void Main(string[] args)
{
CancelReason ad = new CancelReason();
ad.BusinessLineID = 1;
ad.CancelReasonCodeID = 2;
ad.CancelRefund = "C";
ad.CompanyID = 0;
ad.DBOperation = 1;
ad.Description = "test";
ad.IsActive = "Y";
ad.ReasonCode = "TestCode";
ad.UpdateStamp = new byte[] { 1, 2, 3, 4 };
DataTable dt = ad.ConvertToDataTable(s => new { s.DBOperation, s.BusinessLineID, s.LoggedInUser }, r => new { Refund = r.CancelRefund, Company = r.CompanyID });
}
}

how to call the generic method IEnumerator<> IEnumerable<>.GetEnumerator()?

For Some debug i need to get the list of SqlDataRecord generated by the method IEnumerator IEnumerable.GetEnumerator() of the class TVPDataCollection
this code :
TVPDataCollection<AttributiDocumento> oAttributiDocumentoList = new TVPDataCollection<AttributiDocumento>();
AttributiDocumento doc1 = new AttributiDocumento();
AttributiDocumento doc2 = new AttributiDocumento();
oAttributiDocumentoList.Add(doc1);
oAttributiDocumentoList.Add(doc2);
var x = oAttributiDocumentoList.GetEnumerator();
x is a list of AttributiDocumento, but i need a list of SqlDataRecord because i want to inspect the values. what's the way to call the GetEnumerator() that returns SqlDataRecord?
public class TVPDataCollection<T> : List<T>, IEnumerable<SqlDataRecord> where T : class
{
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
List<SqlMetaData> records = new List<SqlMetaData>();
var properties = typeof(T).GetProperties();
foreach (var prop in properties)
{
SqlType oSqlType = GetSqlType(prop);
if (oSqlType.UseSize)
records.Add(new SqlMetaData(prop.Name, oSqlType.SqlDbType, oSqlType.Size));
else
records.Add(new SqlMetaData(prop.Name, oSqlType.SqlDbType));
}
SqlDataRecord oSqlDataRecord = new SqlDataRecord(records.ToArray());
foreach (T data in this)
{
for (int i = 0; i < properties.Length; i++)
{
oSqlDataRecord.SetValue(i, properties[i].GetValue(data, null));
}
yield return oSqlDataRecord;
}
}
}
public class AttributiDocumento
{
public int IdProvPart { get; set; }
//uso stringa in quanto con data agigunge 2 ore del fuso orario
public DateTime Data { get; set; }
public int Articolo { get; set; }
public int ExArticolo { get; set; }
public int DocVer { get; set; }
[LenAttribute(255)]
public string Altro { get; set; }
public AttributiDocumento()
{
this.Data = new DateTime(1900, 1, 1);
this.Altro = string.Empty;
}
}
To do exactly what you are asking for you need to cast oAttributiDocumentoList to the (IEnumerable<SqlDataRecord>) like this:
var x = ((IEnumerable<SqlDataRecord>)oAttributiDocumentoList).GetEnumerator();
But there are some disadvantages working with Enumerators.
Usually you need to access elements of your enumerable. To do so just use foreach loop.
foreach(var record in ((IEnumerable<SqlDataRecord>)oAttributiDocumentoList)) {
//Do whatever you want with record
}
If you still prefer to stick with .GetEnumerator(); do not forget to dispose it at the end or embrace in using.

LINQ result to dataset in C#: Unable to cast AnonymousType to DataSet

I want to fetch my result and convert it to Dataset. My code is :
var res =
from i in dbconnect.tblManageDates
where i.internationalCode == _international
select new
{
i.companyId,
i.endDate,
i.startDate,
i.dateId
};
_result = (DataSet)res;
When I fetch it to Dataset I get this error:
Unable to cast object of type
'System.Data.Linq.DataQuery1[<>f__AnonymousType04[System.String,System.String,System.String,System.Int32]]'
to type 'System.Data.DataSet'.
Try to use such extension:
public static class Extesions
{
public static DataSet ToDataSet<T>(this IList<T> list)
{
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, ColType);
}
//go through each property on T and add each value to the table
foreach (T item in list)
{
DataRow row = t.NewRow();
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
t.Rows.Add(row);
}
return ds;
}
}
Usage:
public class Entity
{
public int CompanyId { get; set; }
public DateTime EndDate { get; set; }
public DateTime StartDate { get; set; }
public int DateId { get; set; }
}
// ...
List<Entity> res = dbconnect.tblManageDates.Where(i => i.internationalCode == _international).Select(i => new Entity
{
CompanyId = i.companyId,
EndDate = i.endDate,
StartDate = i.startDate,
DateId = i.dateId
}).ToList();
DataSet dataSet = res.ToDataSet();

Categories