Can i store serializable array data in DataColumn? - c#

I am trying to automatically convert object's properties to DataTable (object is array and has properties that instantiated from special class which has value type).
The code:
static public DataTable f_GetDataTableFromClassObject(object _objInstance)
{
// geri dönecek datatable
DataTable dataTable = new DataTable();
// nesnenin propertyleri içinde dolanalım ve datatable içine kolon olarak ekleyelim.
foreach (var p in f_GetProperties(_objInstance))
{
if (p.PropertyType.IsArray)
{
if (p.PropertyType.BaseType.Attributes.ToString().IndexOf("Serializable")>-1)
{
// Now i want to store to DataColumn this properties which is instantiated DifferentClass[] and Serializable
}
}
else
{
dataTable.Columns.Add(new DataColumn(p.Name, p.PropertyType));
}
}
// ve tablomuz.
return dataTable;
}
What should i do to store this Array in DataColumn?

class Program
{
static void Main(string[] args)
{
Person cenk = new Person() { adi = "Cenk", yasi = 18 };
List<Person> lst = new List<Person>()
{
cenk,
new Person() {adi = "Cem", yasi = 17, harfler = new[] {"a","b","c"}},
new Person() {adi = "Canan", yasi = 16, harfler = new[] {"a","b","c"}}
};
DataTable dataTable = new DataTable();
PropertyInfo[] pinfo = props();
//var s = pinfo.Select(p => dataTable.Columns.Add(new DataColumn(p.Name, (p.PropertyType.FullName).GetType())));
foreach (var p in pinfo)
{
dataTable.Columns.Add(new DataColumn(p.Name, p.PropertyType));
}
foreach (Person person in lst)
{
DataRow dr = dataTable.NewRow();
foreach (PropertyInfo info in person.GetType().GetProperties())
{
object oo = person.GetType().GetProperty(info.Name).GetValue(person, null);
dr[info.Name] = oo;
}
dataTable.Rows.Add(dr);
}
}
static public PropertyInfo[] props()
{
return (new Person()).GetType().GetProperties();
}
}
public class Person
{
public string adi { get; set; }
public int yasi { get; set; }
public string[] harfler { get; set; }
}

Related

CsvHelper write mapper one property to multiple columns

I'm using csvHelper (version 2.8.4) to write a class to csv.
My class looks like this:
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict{ get; set; }
}
Is it possible to write a mapper that maps Dict property to multiple columns? using some sort of converter?
for example if the class has the values:
Amount = 15
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
I want the resulting csv to be:
Amount,a1,b1
15,a2,b2
Thanks!
Possibly the easiest way is going to be to manually write out the dictionary part.
*** Update to work with CsvHelper Version 2.8.4 ***
void Main()
{
var records = new List<classA>
{
new classA {
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
}
};
using (var csv = new CsvWriter(Console.Out))
{
var dict = records.First().Dict;
var properties = typeof(classA).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.Name);
}
}
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.GetValue(record));
}
}
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
// You can define other methods, fields, classes and namespaces here
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
*** Works for current Version 27.2.1 ***
void Main()
{
var records = new List<classA>
{
new classA { Amount = 15, Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"} },
};
using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
{
var dict = records.First().Dict;
csv.WriteHeader<classA>();
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
csv.WriteRecord(record);
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
As mentioned in linked question, you may use ExpandoObject to serialize dictionary.
The following code will work for writing to CSV only, it's converting classA objects to ExpandoObject during serialization, including Amount property which is added manually.
public static List<dynamic> ToExpandoObjects(IReadOnlyList<classA> aObjects)
{
var allKeys = aObjects
.SelectMany(a => a.Dict.Keys)
.Distinct()
.ToHashSet();
var result = new List<dynamic>();
foreach (var a in aObjects)
{
var asExpando = new ExpandoObject();
var asDictionary = (IDictionary<string, object>)asExpando;
asDictionary[nameof(classA.Amount)] = a.Amount;
foreach (var key in allKeys)
{
if(a.Dict.TryGetValue(key, out var value))
asDictionary[key] = value;
else
asDictionary[key] = null;
}
result.Add(asExpando);
}
return result;
}
...
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
E.g. called as:
var records = new[] {
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
},
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["c1"] = "c2",["b1"] = "b2"}
}
};
StringBuilder sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
Console.WriteLine(sb.ToString());
produces
Amount
a1
b1
c1
15
a2
b2
15
b2
c2

How do I convert Dataset to model <T> - for excel data driven tests

I have fetched data from excel sheet and it is having all the values in Dataset now I ave DataModel type List and I want to return that type and then fetch data but I'm finding difficulty in that
public class TestDataModel
{
public TestDataModel() { }
[DataNames("TestName")]
public string TestName { get; set; }
[DataNames("productId")]
public int productId { get; set; }
[DataNames("orderId")]
public int orderId { get; set; }
[DataNames("designMethod")]
public string designMethod { get; set; }
[DataNames("signedIn")]
public bool signedIn { get; set; }
[DataNames("increaseBasketQty")]
public bool increaseBasketQty { get; set; }
[DataNames("signedInCMS")]
public bool signedInCMS { get; set; }
[DataNames("editable")]
public bool editable { get; set; }
[DataNames("_site")]
public string _site { get; set; }
[DataNames("paymentOptions")]
public string paymentOptions { get; set; }
[DataNames("checkInVoice")]
public string checkInVoice { get; set; }
[DataNames("navigateToDesign")]
public string navigateToDesign { get; set; }
[DataNames("checkOrderAuthorsie")]
public string checkOrderAuthorsie { get; set; }
[DataNames("checkSplitOrder")]
public string checkSplitOrder { get; set; }
[DataNames("SiteId")]
public string SiteId { get; set; }
[DataNames("SiteUrl")]
public string SiteUrl { get; set; }
[DataNames("CultureCode")]
public string CultureCode { get; set; }
[DataNames("SiteGroupId")]
public string SiteGroupId { get; set; }
[DataNames("NickName")]
public string NickName { get; set; }
[DataNames("byCard")]
public string byCard { get; set; }
[DataNames("payLater")]
public string payLater { get; set; }
[DataNames("sliceIt")]
public string sliceIt { get; set; }
[DataNames("portal")]
public string portal { get; set; }
[DataNames("delivery")]
public string delivery { get; set; }
}
Function for fetching Data from Excel
public static IList<TestDataModel> GetAllTestData(string keyName)
{
DataSet ds = new DataSet();
DataNamesMapper<TestDataModel> mapper = new DataNamesMapper<TestDataModel>();
DataTable dataTableALL = new DataTable();
List<TestDataModel> persons = new List<TestDataModel>();
using (var connection = new
OdbcConnection(TestDataFileConnection()))
{
connection.Open();
OdbcCommand cmd = new OdbcCommand();
cmd.Connection = connection;
System.Data.DataTable dtSheet = null;
dtSheet = connection.GetSchema(OdbcMetaDataCollectionNames.Tables, null);
foreach (DataRow row in dtSheet.Rows)
{
string sheetName = row["TABLE_NAME"].ToString();
if (!sheetName.EndsWith("$"))
continue;
// Query each excel sheet.
var query = string.Format("select * from [{0}] where TestName = '{1}'", sheetName, keyName);
cmd.CommandText = query;
DataTable dt = new DataTable();
dt.TableName = sheetName;
OdbcDataAdapter da = new OdbcDataAdapter(cmd);
da.Fill(dt);
//dataTableALL.Merge(dt);
//ds.Merge(dt);
ds.Tables.Add(dt);
}
cmd = null;
connection.Close();
}
DataTable flatTable = null;
string ID = "TestName";
for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable dt = ds.Tables[i];
if (i == 0)
{
flatTable = dt.AsEnumerable().CopyToDataTable();
}
else
{
DataColumn[] columns = dt.Columns.Cast<DataColumn>().ToArray();
foreach (DataColumn col in columns)
{
if (col.ColumnName != ID)
{
flatTable.Columns.Add(col.ColumnName, col.DataType);
}
}
var joins = from t1 in flatTable.AsEnumerable()
join t2 in dt.AsEnumerable()
on t1.Field<string>(ID) equals t2.Field<string>(ID)
select new { t1 = t1, t2 = t2 };
foreach (var join in joins)
{
foreach (string column in columns.Cast<DataColumn>().Select(x => x.ColumnName))
{
if (column != ID)
{
join.t1[column] = join.t2[column];
}
}
}
}
//return testDataModelList.ToList();
//return ds;
}
var test = mapper.Map(dataTableALL).ToList();
//persons = mapper.Map(ds.Tables[0]).ToList();
persons = mapper.Map(flatTable).ToList();
return persons.ToList();
}
In above function I'm not able to understand how do I convert the DS values to TestDataModel List for return
Function Call:
var param = AccessExcelData.GetAllTestData<TestDataModel>("BOL_GB_PlaceOrder_By_PayLater_Using_Klarna_With_BillingAddress_Excel");
Try this.
var testDataModelList = ds.Tables[0].AsEnumerable()
.Select(dataRow => new TestDataModel
{
TestName = dataRow.Field<string>("TestName"),
productId = (int)dataRow["productId"],
...
}).ToList();
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
DataSet ds = new DataSet();
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof(int));
dt1.Columns.Add("ColA", typeof(string));
dt1.Columns.Add("ColB", typeof(string));
dt1.Rows.Add(new object[] { 1, "100", "1000" });
dt1.Rows.Add(new object[] { 2, "101", "1001" });
dt1.Rows.Add(new object[] { 3, "102", "1002" });
ds.Tables.Add(dt1);
DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(int));
dt2.Columns.Add("ColC", typeof(string));
dt2.Columns.Add("ColD", typeof(string));
dt2.Rows.Add(new object[] { 1, "200", "2000" });
dt2.Rows.Add(new object[] { 2, "201", "2001" });
dt2.Rows.Add(new object[] { 3, "302", "2002" });
ds.Tables.Add(dt2);
DataTable dt3 = new DataTable();
dt3.Columns.Add("ID", typeof(int));
dt3.Columns.Add("ColE", typeof(string));
dt3.Columns.Add("ColF", typeof(string));
dt3.Rows.Add(new object[] { 1, "300", "3000" });
dt3.Rows.Add(new object[] { 2, "301", "3001" });
dt3.Rows.Add(new object[] { 3, "302", "3002" });
ds.Tables.Add(dt3);
DataTable dt4 = new DataTable();
dt4.Columns.Add("ID", typeof(int));
dt4.Columns.Add("ColG", typeof(string));
dt4.Columns.Add("ColH", typeof(string));
dt4.Rows.Add(new object[] { 1, "400", "4000" });
dt4.Rows.Add(new object[] { 2, "401", "4001" });
dt4.Rows.Add(new object[] { 3, "402", "4002" });
ds.Tables.Add(dt4);
DataTable flatTable = null;
string ID = "ID";
for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable dt = ds.Tables[i];
if (i == 0)
{
flatTable = dt.AsEnumerable().CopyToDataTable();
}
else
{
DataColumn[] columns = dt.Columns.Cast<DataColumn>().ToArray();
foreach (DataColumn col in columns)
{
if (col.ColumnName != ID)
{
flatTable.Columns.Add(col.ColumnName, col.DataType);
}
}
var joins = from t1 in flatTable.AsEnumerable()
join t2 in dt.AsEnumerable()
on t1.Field<int>(ID) equals t2.Field<int>(ID)
select new { t1 = t1, t2 = t2 };
foreach (var join in joins)
{
foreach (string column in columns.Cast<DataColumn>().Select(x => x.ColumnName))
{
if (column != ID)
{
join.t1[column] = join.t2[column];
}
}
}
}
}
string[] filteredColumns = { "ColA", "ColC", "ColE", "ColG" };
int[] filteredIndexes = filteredColumns.Select(x => flatTable.Columns.Cast<DataColumn>().Where(y => x == y.ColumnName).First().Ordinal).ToArray();
DataTable filteredTable = new DataTable();
foreach (int index in filteredIndexes)
{
filteredTable.Columns.Add(flatTable.Columns[index].ColumnName, flatTable.Columns[index].DataType);
}
foreach(DataRow row in flatTable.AsEnumerable())
{
filteredTable.Rows.Add(filteredIndexes.Select(y => row[y]).ToArray());
};
}
}
}

How to convert Datatable to class list c# [duplicate]

Currently, I'm using:
DataTable dt = CreateDataTableInSomeWay();
List<DataRow> list = new List<DataRow>();
foreach (DataRow dr in dt.Rows)
{
list.Add(dr);
}
Is there a better/magic way?
If you're using .NET 3.5, you can use DataTableExtensions.AsEnumerable (an extension method) and then if you really need a List<DataRow> instead of just IEnumerable<DataRow> you can call Enumerable.ToList:
IEnumerable<DataRow> sequence = dt.AsEnumerable();
or
using System.Linq;
...
List<DataRow> list = dt.AsEnumerable().ToList();
List<Employee> emp = new List<Employee>();
//Maintaining DataTable on ViewState
//For Demo only
DataTable dt = ViewState["CurrentEmp"] as DataTable;
//read data from DataTable
//using lamdaexpression
emp = (from DataRow row in dt.Rows
select new Employee
{
_FirstName = row["FirstName"].ToString(),
_LastName = row["Last_Name"].ToString()
}).ToList();
With C# 3.0 and System.Data.DataSetExtensions.dll,
List<DataRow> rows = table.Rows.Cast<DataRow>().ToList();
You could use
List<DataRow> list = new List<DataRow>(dt.Select());
dt.Select() will return all rows in your table, as an array of datarows, and the List constructor accepts that array of objects as an argument to initially fill your list with.
If you just want a list of values from the "ID" int field returned, you could use...
List<int> ids = (from row in dt.AsEnumerable() select Convert.ToInt32(row["ID"])).ToList();
You can create a extension function as :
public static List<T> ToListof<T>(this DataTable dt)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var columnNames = dt.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToList();
var objectProperties = typeof(T).GetProperties(flags);
var targetList = dt.AsEnumerable().Select(dataRow =>
{
var instanceOfT = Activator.CreateInstance<T>();
foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
{
properties.SetValue(instanceOfT, dataRow[properties.Name], null);
}
return instanceOfT;
}).ToList();
return targetList;
}
var output = yourDataInstance.ToListof<targetModelType>();
I have added some modification to the code from this answer (https://stackoverflow.com/a/24588210/4489664) because for nullable Types it will return exception
public static List<T> DataTableToList<T>(this DataTable table) where T: new()
{
List<T> list = new List<T>();
var typeProperties = typeof(T).GetProperties().Select(propertyInfo => new
{
PropertyInfo = propertyInfo,
Type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType
}).ToList();
foreach (var row in table.Rows.Cast<DataRow>())
{
T obj = new T();
foreach (var typeProperty in typeProperties)
{
object value = row[typeProperty.PropertyInfo.Name];
object safeValue = value == null || DBNull.Value.Equals(value)
? null
: Convert.ChangeType(value, typeProperty.Type);
typeProperty.PropertyInfo.SetValue(obj, safeValue, null);
}
list.Add(obj);
}
return list;
}
using System.Data;
var myEnumerable = myDataTable.AsEnumerable();
List<MyClass> myClassList =
(from item in myEnumerable
select new MyClass{
MyClassProperty1 = item.Field<string>("DataTableColumnName1"),
MyClassProperty2 = item.Field<string>("DataTableColumnName2")
}).ToList();
Again, using 3.5 you may do it like:
dt.Select().ToList()
BRGDS
// this is better suited for expensive object creation/initialization
IEnumerable<Employee> ParseEmployeeTable(DataTable dtEmployees)
{
var employees = new ConcurrentBag<Employee>();
Parallel.ForEach(dtEmployees.AsEnumerable(), (dr) =>
{
employees.Add(new Employee()
{
_FirstName = dr["FirstName"].ToString(),
_LastName = dr["Last_Name"].ToString()
});
});
return employees;
}
A more 'magic' way, and doesn't need .NET 3.5.
If, for example, DBDatatable was returning a single column of Guids (uniqueidentifier in SQL) then you could use:
Dim gList As New List(Of Guid)
gList.AddRange(DirectCast(DBDataTable.Select(), IEnumerable(Of Guid)))
DataTable dt; // datatable should contains datacolumns with Id,Name
List<Employee> employeeList=new List<Employee>(); // Employee should contain EmployeeId, EmployeeName as properties
foreach (DataRow dr in dt.Rows)
{
employeeList.Add(new Employee{EmployeeId=dr.Id,EmplooyeeName=dr.Name});
}
The Easiest way of Converting the DataTable into the Generic list of class
using Newtonsoft.Json;
var json = JsonConvert.SerializeObject(dataTable);
var model = JsonConvert.DeserializeObject<List<ClassName>>(json);
DataTable.Select() doesnt give the Rows in the order they were present in the datatable.
If order is important I feel iterating over the datarow collection and forming a List is the right way to go or you could also use overload of DataTable.Select(string filterexpression, string sort).
But this overload may not handle all the ordering (like order by case ...) that SQL provides.
/* This is a generic method that will convert any type of DataTable to a List
*
*
* Example : List< Student > studentDetails = new List< Student >();
* studentDetails = ConvertDataTable< Student >(dt);
*
* Warning : In this case the DataTable column's name and class property name
* should be the same otherwise this function will not work properly
*/
The following are the two functions in which if we pass a
DataTable
and a user defined class.
It will then return the List of that class with the DataTable data.
public static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = new List<T>();
foreach (DataRow row in dt.Rows)
{
T item = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static T GetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj = Activator.CreateInstance<T>();
foreach (DataColumn column in dr.Table.Columns)
{
foreach (PropertyInfo pro in temp.GetProperties())
{
//in case you have a enum/GUID datatype in your model
//We will check field's dataType, and convert the value in it.
if (pro.Name == column.ColumnName){
try
{
var convertedValue = GetValueByDataType(pro.PropertyType, dr[column.ColumnName]);
pro.SetValue(obj, convertedValue, null);
}
catch (Exception e)
{
//ex handle code
throw;
}
//pro.SetValue(obj, dr[column.ColumnName], null);
}
else
continue;
}
}
return obj;
}
This method will check the datatype of field, and convert dataTable value in to that datatype.
private static object GetValueByDataType(Type propertyType, object o)
{
if (o.ToString() == "null")
{
return null;
}
if (propertyType == (typeof(Guid)) || propertyType == typeof(Guid?))
{
return Guid.Parse(o.ToString());
}
else if (propertyType == typeof(int) || propertyType.IsEnum)
{
return Convert.ToInt32(o);
}
else if (propertyType == typeof(decimal) )
{
return Convert.ToDecimal(o);
}
else if (propertyType == typeof(long))
{
return Convert.ToInt64(o);
}
else if (propertyType == typeof(bool) || propertyType == typeof(bool?))
{
return Convert.ToBoolean(o);
}
else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
{
return Convert.ToDateTime(o);
}
return o.ToString();
}
To call the preceding method, use the following syntax:
List< Student > studentDetails = new List< Student >();
studentDetails = ConvertDataTable< Student >(dt);
Change the Student class name and dt value based on your requirements. In this case the DataTable column's name and class property name should be the same otherwise this function will not work properly.
lPerson = dt.AsEnumerable().Select(s => new Person()
{
Name = s.Field<string>("Name"),
SurName = s.Field<string>("SurName"),
Age = s.Field<int>("Age"),
InsertDate = s.Field<DateTime>("InsertDate")
}).ToList();
Link to working DotNetFiddle Example
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Data.DataSetExtensions;
public static void Main()
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("SurName", typeof(string));
dt.Columns.Add("Age", typeof(int));
dt.Columns.Add("InsertDate", typeof(DateTime));
var row1= dt.NewRow();
row1["Name"] = "Adam";
row1["SurName"] = "Adam";
row1["Age"] = 20;
row1["InsertDate"] = new DateTime(2020, 1, 1);
dt.Rows.Add(row1);
var row2 = dt.NewRow();
row2["Name"] = "John";
row2["SurName"] = "Smith";
row2["Age"] = 25;
row2["InsertDate"] = new DateTime(2020, 3, 12);
dt.Rows.Add(row2);
var row3 = dt.NewRow();
row3["Name"] = "Jack";
row3["SurName"] = "Strong";
row3["Age"] = 32;
row3["InsertDate"] = new DateTime(2020, 5, 20);
dt.Rows.Add(row3);
List<Person> lPerson = new List<Person>();
lPerson = dt.AsEnumerable().Select(s => new Person()
{
Name = s.Field<string>("Name"),
SurName = s.Field<string>("SurName"),
Age = s.Field<int>("Age"),
InsertDate = s.Field<DateTime>("InsertDate")
}).ToList();
foreach(Person pers in lPerson)
{
Console.WriteLine("{0} {1} {2} {3}", pers.Name, pers.SurName, pers.Age, pers.InsertDate);
}
}
public class Person
{
public string Name { get; set; }
public string SurName { get; set; }
public int Age { get; set; }
public DateTime InsertDate { get; set; }
}
}
Use System.Data namespace then you will get .AsEnumerable().
This worked for me:
Need at least .Net Framework 3.5,
Code below displays DataRow turned to Generic.IEnumerable, comboBox1 has been used for a better illustration.
using System.Linq;
DataTable dt = new DataTable();
dt = myClass.myMethod();
List<object> list = (from row in dt.AsEnumerable() select (row["name"])).ToList();
comboBox1.DataSource = list;
Output
public class ModelUser
{
#region Model
private string _username;
private string _userpassword;
private string _useremail;
private int _userid;
/// <summary>
///
/// </summary>
public int userid
{
set { _userid = value; }
get { return _userid; }
}
/// <summary>
///
/// </summary>
public string username
{
set { _username = value; }
get { return _username; }
}
/// <summary>
///
/// </summary>
public string useremail
{
set { _useremail = value; }
get { return _useremail; }
}
/// <summary>
///
/// </summary>
public string userpassword
{
set { _userpassword = value; }
get { return _userpassword; }
}
#endregion Model
}
public List<ModelUser> DataTableToList(DataTable dt)
{
List<ModelUser> modelList = new List<ModelUser>();
int rowsCount = dt.Rows.Count;
if (rowsCount > 0)
{
ModelUser model;
for (int n = 0; n < rowsCount; n++)
{
model = new ModelUser();
model.userid = (int)dt.Rows[n]["userid"];
model.username = dt.Rows[n]["username"].ToString();
model.useremail = dt.Rows[n]["useremail"].ToString();
model.userpassword = dt.Rows[n]["userpassword"].ToString();
modelList.Add(model);
}
}
return modelList;
}
static DataTable GetTable()
{
// Here we create a DataTable with four columns.
DataTable table = new DataTable();
table.Columns.Add("userid", typeof(int));
table.Columns.Add("username", typeof(string));
table.Columns.Add("useremail", typeof(string));
table.Columns.Add("userpassword", typeof(string));
// Here we add five DataRows.
table.Rows.Add(25, "Jame", "Jame#hotmail.com", DateTime.Now.ToString());
table.Rows.Add(50, "luci", "luci#hotmail.com", DateTime.Now.ToString());
table.Rows.Add(10, "Andrey", "Andrey#hotmail.com", DateTime.Now.ToString());
table.Rows.Add(21, "Michael", "Michael#hotmail.com", DateTime.Now.ToString());
table.Rows.Add(100, "Steven", "Steven#hotmail.com", DateTime.Now.ToString());
return table;
}
protected void Page_Load(object sender, EventArgs e)
{
List<ModelUser> userList = new List<ModelUser>();
DataTable dt = GetTable();
userList = DataTableToList(dt);
gv.DataSource = userList;
gv.DataBind();
}[enter image description here][1]
</asp:GridView>
</div>
We can use a Generic Method for converting DataTable to List instead of manually converting a DataTable to List.
Note: DataTable's ColumnName and Type's PropertyName should be same.
Call the below Method:
long result = Utilities.ConvertTo<Student>(dt ,out listStudent);
// Generic Method
public class Utilities
{
public static long ConvertTo<T>(DataTable table, out List<T> entity)
{
long returnCode = -1;
entity = null;
if (table == null)
{
return -1;
}
try
{
entity = ConvertTo<T>(table.Rows);
returnCode = 0;
}
catch (Exception ex)
{
returnCode = 1000;
}
return returnCode;
}
static List<T> ConvertTo<T>(DataRowCollection rows)
{
List<T> list = null;
if (rows != null)
{
list = new List<T>();
foreach (DataRow row in rows)
{
T item = CreateItem<T>(row);
list.Add(item);
}
}
return list;
}
static T CreateItem<T>(DataRow row)
{
string str = string.Empty;
string strObj = string.Empty;
T obj = default(T);
if (row != null)
{
obj = Activator.CreateInstance<T>();
strObj = obj.ToString();
NameValueCollection objDictionary = new NameValueCollection();
foreach (DataColumn column in row.Table.Columns)
{
PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);
if (prop != null)
{
str = column.ColumnName;
try
{
objDictionary.Add(str, row[str].ToString());
object value = row[column.ColumnName];
Type vType = obj.GetType();
if (value == DBNull.Value)
{
if (vType == typeof(int) || vType == typeof(Int16)
|| vType == typeof(Int32)
|| vType == typeof(Int64)
|| vType == typeof(decimal)
|| vType == typeof(float)
|| vType == typeof(double))
{
value = 0;
}
else if (vType == typeof(bool))
{
value = false;
}
else if (vType == typeof(DateTime))
{
value = DateTime.MaxValue;
}
else
{
value = null;
}
prop.SetValue(obj, value, null);
}
else
{
prop.SetValue(obj, value, null);
}
}
catch(Exception ex)
{
}
}
}
PropertyInfo ActionProp = obj.GetType().GetProperty("ActionTemplateValue");
if (ActionProp != null)
{
object ActionValue = objDictionary;
ActionProp.SetValue(obj, ActionValue, null);
}
}
return obj;
}
}
You can use a generic method like that for datatable to generic list
public static List<T> DataTableToList<T>(this DataTable table) where T : class, new()
{
try
{
List<T> list = new List<T>();
foreach (var row in table.AsEnumerable())
{
T obj = new T();
foreach (var prop in obj.GetType().GetProperties())
{
try
{
PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
if (propertyInfo.PropertyType.IsEnum)
{
propertyInfo.SetValue(obj, Enum.Parse(propertyInfo.PropertyType, row[prop.Name].ToString()));
}
else
{
propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null);
}
}
catch
{
continue;
}
}
list.Add(obj);
}
return list;
}
catch
{
return null;
}
}
Converting DataTable to Generic Dictionary
public static Dictionary<object,IList<dynamic>> DataTable2Dictionary(DataTable dt)
{
Dictionary<object, IList<dynamic>> dict = new Dictionary<dynamic, IList<dynamic>>();
foreach(DataColumn column in dt.Columns)
{
IList<dynamic> ts = dt.AsEnumerable()
.Select(r => r.Field<dynamic>(column.ToString()))
.ToList();
dict.Add(column, ts);
}
return dict;
}
Use Extension :
public static class Extensions
{
#region Convert Datatable To List
public static IList<T> ToList<T>(this DataTable table) where T : new()
{
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
IList<T> result = new List<T>();
foreach (var row in table.Rows)
{
var item = CreateItemFromRow<T>((DataRow)row, properties);
result.Add(item);
}
return result;
}
private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
{
T item = new T();
foreach (var property in properties)
{
property.SetValue(item, row[property.Name], null);
}
return item;
}
#endregion
}
To assign the DataTable rows to the generic List of class
List<Candidate> temp = new List<Candidate>();//List that holds the Candidate Class,
//Note:The Candidate class contains RollNo,Name and Department
//tb is DataTable
temp = (from DataRow dr in tb.Rows
select new Candidate()
{
RollNO = Convert.ToInt32(dr["RollNO"]),
Name = dr["Name"].ToString(),
Department = dr["Department"].ToString(),
}).ToList();
you can use following two Generic functions
private static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = new List<T>();
foreach (DataRow row in dt.Rows)
{
T item = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static T GetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj = Activator.CreateInstance<T>();
foreach (DataColumn column in dr.Table.Columns)
{
foreach (PropertyInfo pro in temp.GetProperties())
{
if (pro.Name == column.ColumnName)
pro.SetValue(obj, dr[column.ColumnName].ToString(), null);
else
continue;
}
}
return obj;
}
and use it as following
List<StudentScanExamsDTO> studentDetails = ConvertDataTable<StudentScanExamsDTO>(dt);
If anyone want's to create custom function to convert datatable to list
class Program
{
static void Main(string[] args)
{
DataTable table = GetDataTable();
var sw = new Stopwatch();
sw.Start();
LinqMethod(table);
sw.Stop();
Console.WriteLine("Elapsed time for Linq Method={0}", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
ForEachMethod(table);
sw.Stop();
Console.WriteLine("Elapsed time for Foreach method={0}", sw.ElapsedMilliseconds);
Console.ReadKey();
}
private static DataTable GetDataTable()
{
var table = new DataTable();
table.Columns.Add("ID", typeof(double));
table.Columns.Add("CategoryName", typeof(string));
table.Columns.Add("Active", typeof(double));
var rand = new Random();
for (int i = 0; i < 100000; i++)
{
table.Rows.Add(i, "name" + i, rand.Next(0, 2));
}
return table;
}
private static void LinqMethod(DataTable table)
{
var list = table.AsEnumerable()
.Skip(1)
.Select(dr =>
new Category
{
Id = Convert.ToInt32(dr.Field<double>("ID")),
CategoryName = dr.Field<string>("CategoryName"),
IsActive =
dr.Field<double>("Active") == 1 ? true : false
}).ToList();
}
private static void ForEachMethod(DataTable table)
{
var categoryList = new List<Category>(table.Rows.Count);
foreach (DataRow row in table.Rows)
{
var values = row.ItemArray;
var category = new Category()
{
Id = Convert.ToInt32(values[0]),
CategoryName = Convert.ToString(values[1]),
IsActive = (double)values[2] == 1 ? true : false
};
categoryList.Add(category);
}
}
private class Category
{
public int Id { get; set; }
public string CategoryName { get; set; }
public bool IsActive { get; set; }
}
}
If we execute above code, Foreach method finishes in 56ms while linq one takes 101ms ( for 1000 records).
So Foreach method is better to use.
Source:Ways to Convert Datatable to List in C# (with performance test example)
try this using Newtonsoft Json:
var json = JsonConvert.SerializeObject(dataTable);
var YourConvertedDataType = JsonConvert.DeserializeObject<YourDataType>(json);
To get List of values instead of ItemArray, do this:
List<string> s = dt.AsEnumerable().Select(x => x[0].ToString()).ToList();
The above assumes that you want list of string values from column 0.

Create distinct expando object list

I have created a method which will create dynamic object list from an object list according to property list. In this case I have completed such task using Expandoobject. But I have failed to create distinct list of such expando object list. Please visit the following fidder and see my code.
public class Program
{
public static void Main()
{
var _dynamicObjectList = new List<Student>();
for (int i = 0; i < 5; i++)
{
_dynamicObjectList.Add(new Student { ID = i, Name = "stu" + i, Address = "address" + i, AdmissionDate = DateTime.Now.AddDays(i) , Age=15, FatherName="Jamal"+i, MotherName = "Jamila"+i});
}
//create again for checking distinct list
for (int i = 0; i < 5; i++)
{
_dynamicObjectList.Add(new Student { ID = i, Name = "stu" + i, Address = "address" + i, AdmissionDate = DateTime.Now.AddDays(i), Age = 15, FatherName = "Jamal" + i, MotherName = "Jamila" + i });
}
// var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,Name,Address");
// var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,FatherName,Address");
var returnList = test2.GetDdlData<Object>(_dynamicObjectList, "ID,Name,FatherName,MotherName,Age");
string strSerializeData = JsonConvert.SerializeObject(returnList);
Console.WriteLine(strSerializeData);
Console.ReadLine();
}
}
public class Student
{
public int? ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime AdmissionDate { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public int Age { get; set; }
}
public static class test2
{
public static IList GetDdlData<T>(this IEnumerable<T> source, string userParams)
{
try
{
List<string> otherProperties = userParams.Split(',').ToList();
Dictionary<string, PropertyInfo> parentPropertyInfo = new Dictionary<string, PropertyInfo>();
Dictionary<string, Type> parentType = new Dictionary<string, Type>();
var dynamicObjectList = (from k in source select k).ToList();
if (dynamicObjectList.Count() > 0)
{
//if parentField exists then system will handle parent property
if (otherProperties.Count > 0)
{
foreach (string otherProperty in otherProperties)
{
//get parent field property info
PropertyInfo _info = dynamicObjectList[0].GetType().GetProperty(otherProperty);
parentPropertyInfo.Add(otherProperty, _info);
//get parent field propertyType
Type pType = Nullable.GetUnderlyingType(_info.PropertyType) ?? _info.PropertyType;
parentType.Add(otherProperty, pType);
}
}
}
//return List
IList<object> objList = new List<object>();
foreach (T obj in source)
{
var dynamicObj = new ExpandoObject() as IDictionary<string, Object>;
foreach (string otherProperty in otherProperties)
{
PropertyInfo objPropertyInfo = parentPropertyInfo.FirstOrDefault(m => m.Key == otherProperty).Value;
Type objPropertyType = parentType.FirstOrDefault(m => m.Key == otherProperty).Value;
Object data = (objPropertyInfo.GetValue(obj, null) == null) ? null : Convert.ChangeType(objPropertyInfo.GetValue(obj, null), objPropertyType, null);
dynamicObj.Add(otherProperty, data);
}
objList.Add(dynamicObj);
}
var returnUniqList = objList.Distinct().ToList();
return returnUniqList;
}
catch (Exception ex)
{
throw ex;
}
}
}
https://dotnetfiddle.net/hCuJwD
Just add the following code in the code block.
foreach(var objTemp in objList) {
bool isNotSimilar = true;
foreach(string property in otherProperties) {
//get sending object property data
object tempFValue = (objTemp as IDictionary < string, Object > )[property];
//get current object property data
object tempCValue = (dynamicObj as IDictionary < string, Object > )[property];
if (!tempFValue.Equals(tempCValue)) {
isNotSimilar = false;
break;
}
}
if (isNotSimilar) {
isDuplicate = true;
break;
}
}
DOTNETFIDDLE

Convert Datatable to strogly Typed Model

I have a model class like this
public class Profile
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string NickName { get; set; }
public string City { get; set; }
public string State { get; set; }
...................... etc
}
And a datatable which is of same type of data. Means columns in datattable will be FirstName,LastName,NickName,City,State. And the data table will have only one row.
Now I want to copy the data in this datatable to Profile model. Right now I am doing like this.
var sp = new Profile();
DataTable dt = ProfileDAL.GetProfile(profileId);
if (profile.Rows.Count > 0)
{
sp.FirstName = ReferenceEquals(dt.Rows[0]["FirstName"], "")
? ""
: dt.Rows[0]["FirstName"].ToString();
sp.LastName = ReferenceEquals(dt.Rows[0]["LastName"], "")
? ""
: dt.Rows[0]["LastName"].ToString();
sp.NickName = ReferenceEquals(dt.Rows[0]["NickName"], "")
? ""
: dt.Rows[0]["NickName"].ToString();
}
is there any elegant way of doing this? Like I have a huge datatable to convert and when I do it like what I am doing now. It will take a long time and a number of lines of code. Can anyone point out anything better?
This what I used that saved me time. I created it as an extension to DataTable. All you have to do is
DataTable dt = ProfileDAL.GetProfile(profileId);
var profile = dt.Rows[0].ToEntity<Profile>(); //<-- new changes
And if you want a list
DataTable dt = ProfileDAL.GetProfiles();
var profiles = dt.ToList<Profile>();
Or get your entity with LINQ
DataTable dt = ProfileDAL.GetProfile(profileId);
var profile = dt.ToList<Profile>().FirstOrDefault();
The class
public static class DataExtensions
{
public static T ToEntity<T>(this DataRow dr) where T : new()
{
DataColumnCollection columns = dr.Table.Columns;
T obj1 = new T();
foreach (PropertyInfo propertyInfo in obj1.GetType().GetProperties())
{
if (columns.Contains(propertyInfo.Name) && dr[propertyInfo.Name] != DBNull.Value)
{
if (propertyInfo.PropertyType.IsGenericType)
{
object obj2 = Convert.ChangeType(dr[propertyInfo.Name], propertyInfo.PropertyType.GetGenericArguments()[0]);
propertyInfo.SetValue((object) obj1, obj2, (object[]) null);
}
else
{
object obj2 = Convert.ChangeType(dr[propertyInfo.Name], propertyInfo.PropertyType);
propertyInfo.SetValue((object) obj1, obj2, (object[]) null);
}
}
}
return obj1;
}
public static List<T> ToList<T>(this DataTable dt) where T : new()
{
List<T> list = new List<T>();
foreach (DataRow dr in (InternalDataCollectionBase) dt.Rows)
list.Add(DataExtensions.ToEntity<T>(dr));
return list;
}
}
here is solution i use this for map data table with entity
or you can use the AutoMapper
IList<Profile> result = new List<Profile>();
result = currentDataTable.AsEnumerable().Select(row => new Profile
{
FirstName = row["FirstName"].ToString(),
LastName = row["LastName"].ToString()
}
).ToList<Profile>();

Categories

Resources