how to exclude some list properties to make data table - c#

In below utility function (list to Data Table), how can I exclude some member of list.
Like, I don't want to send the 2 properties "UniqueKey" & "PointToPointData" to the utility method below,
public class PointDataClone
{
public int DataId { get; set; }
public string UniqueKey { get; set; }
public int Count { get; set; }
public List<PointToPointData> PointToPointData { get; set; }
}
Utility Function,
public static DataTable ToDataTable<T>(this List<T> iList)
{
DataTable dataTable = new DataTable();
PropertyDescriptorCollection propertyDescriptorCollection = TypeDescriptor.GetProperties(typeof(T));
for (int i = 0; i < propertyDescriptorCollection.Count; i++)
{
PropertyDescriptor propertyDescriptor = propertyDescriptorCollection[i];
Type type = propertyDescriptor.PropertyType;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
type = Nullable.GetUnderlyingType(type);
dataTable.Columns.Add(propertyDescriptor.Name, type);
}
object[] values = new object[propertyDescriptorCollection.Count];
foreach (T iListItem in iList)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = propertyDescriptorCollection[i].GetValue(iListItem);
}
dataTable.Rows.Add(values);
}
return dataTable;
}

create an attribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class DontShowMe : Attribute
{
}
You can then use the attribute to annotate your class
public class PointDataClone
{
public int DataId { get; set; }
[DontShowMe]
public string UniqueKey { get; set; }
public int Count { get; set; }
[DontShowMe]
public List<PointToPointData> PointToPointData { get; set; }
}
and modify your function to query the attributes. You will need an additional using statement
using System.ComponentModel;
add this line to your loop
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) type = Nullable.GetUnderlyingType(type);
// test attribute to see if it is shown
if (propertyDescriptor.Attributes.Contains(new DontShowMe())) continue;
dataTable.Columns.Add(propertyDescriptor.Name, type);
You will now have to deal with the fact that your object will have more properties than the datatable has columns. I will leave it to you to manage that little detail.
Hope this helps,
Marc

Please find below Code.
I passed list of string to exclude properties name.
See below Code.
public static DataTable ToDataTableVendorExp<T>(List<T> items,List<string> ExcludeColumnName)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(a => a.PropertyType != typeof(System.Object)).Cast<PropertyInfo>().ToArray();
List<int> lstIgnoreIndex = new List<int>();
int colIndex = 0;
foreach (PropertyInfo prop in Props)
{
//Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
//Setting column names as Property names
string dtcolumname = prop.Name;
//check if property name of list dont need to export then ignore.
if (ExcludeColumnName != null && ExcludeColumnName.IndexOf(dtcolumname) >= 0)
{
lstIgnoreIndex.Add(colIndex);
}
else
{
if (Attribute.IsDefined(prop, typeof(DisplayNameRptAttribute)))
{
var attrvalue = (DisplayNameRptAttribute)prop.GetCustomAttribute(typeof(DisplayNameRptAttribute));
dtcolumname = attrvalue.GetName();
}
dataTable.Columns.Add(dtcolumname, type);
}
colIndex++;
}
//if ignore 3 properties out of 10 then only 7 required.
int totlaproplength = Props.Length;
if (lstIgnoreIndex.Count > 0)
totlaproplength = totlaproplength - lstIgnoreIndex.Count;
foreach (T item in items)
{
var values = new object[totlaproplength];
for (int i = 0; i < Props.Length; i++)
{
if (lstIgnoreIndex.IndexOf(i) >= 0)
continue;
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
if (Props[i].ToString() == "System.DateTime Date")
{
values[i] = String.Format("{0:MM/dd/yyyy}", (Props[i].GetValue(item, null)));
}
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}

Related

How to convert array collection to a dataset c#

Hi have a response class that has three models, all of a certain type...
public class AssociationResponse
{
public AssociationModel ItemDetail {get;set;}
public AssociationModel[] Children {get;set;}
public AssociationModel Parent {get; set;}
public int ErrorCode { get; set; }
public string ErrorMessage { get; set; }
}
Now i am struggling in how to convert the AssociationModel[] Children to a simple dataset, so that i can convert them into datatables and show the results in a tree diagram.. unless anybody knows of a better way?
In my code behind
public AssociationModel ItemDetail { get; set; } = new AssociationModel();
public AssociationModel Parent { get; set; } = new AssociationModel();
public AssociationModel Child { get; set; } = new AssociationModel();
public async Task LoadData(string SerialNumber)
{
try
{
GetAssociationBySerialNumberRequest request = new GetAssociationBySerialNumberRequest()
{
SerialNumber = SerialNumber
};
response = await IAssociation.AssociationGetData(request);
AssociationResponse resp = new AssociationResponse();
if (SerialNumber != null)
{
ItemDetail = response.ItemDetail;
Parent = response.Parent;
**DataSet dset = new DataSet();**
}
}
Any help would be greatful. P.S there are three tables within my [] Children.. So i wanted to somehow access them, i have tried saving to a datatable type, but that doesn't work. any help appreciated.
Edit
The problem, i am having is that i cant seem to convert the arrays to a dataset. Not sure how to do this.
Will this work for you?
I use this extension method to convert IEnumerable to Datatables
public static DataTable ToDataTable<T>(this IList<T> data)
{
var props = TypeDescriptor.GetProperties(typeof(T));
var table = new DataTable();
for (var i = 0; i < props.Count; i++)
{
var prop = props[i];
Type propertyType;
if (prop.PropertyType.IsGenericType &&
prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = prop.PropertyType.GetGenericArguments()[0];
}
else
{
propertyType = prop.PropertyType;
}
table.Columns.Add(prop.Name, propertyType);
}
var values = new object[props.Count];
foreach (var item in data)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Edited
What about this method?
public static DataTable ToDataTable(IList<AssociationModel> data)
{
var props = TypeDescriptor.GetProperties(typeof(AssociationModel));
var table = new DataTable();
for (var i = 0; i < props.Count; i++)
{
var prop = props[i];
Type propertyType;
if (prop.PropertyType.IsGenericType &&
prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = prop.PropertyType.GetGenericArguments()[0];
}
else
{
propertyType = prop.PropertyType;
}
table.Columns.Add(prop.Name, propertyType);
}
var values = new object[props.Count];
foreach (var item in data)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
and your code will change like follow
if (SerialNumber != null)
{
ItemDetail = response.ItemDetail;
Parent = response.Parent;
DataTable dataTable = ToDataTable(response.Children.ToList());
}

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.

How to convert IEnumerable<T> list to Datatable in C#

I am stuck with the following problem:
I normally use the function below to transfer custom data to DataTable but in this case the input data is a class composed of lists. I just need to write in DataTable the first element of each list per row. Could you help me to adjust this function in order to achieve this?
public List<int> xID { get; set; }
public List<string> xName { get; set; }
public List<string> xType { get; set; }
public List<string> xSource { get; set; }
public List<int> xmdID { get; set; }
public List<string> xMDName { get; set; }
public List<string> xUser { get; set; }
public static DataTable ListToDataTable<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, 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;
}
Based in Carra answer I tried the code below but it did not recognize pType type (The type or namespace name 'pType' could not be found (are you missing a using directive or an assembly reference?))
var v = properties[i].GetValue(entity);
Type pType = properties[i].PropertyType;
if (pType.IsGenericType && pType.GetGenericTypeDefinition() == typeof(Nullable<>))
pType = Nullable.GetUnderlyingType(pType);
if (pType.IsEnum)
pType = Enum.GetUnderlyingType(pType);
if (v.GetType().GetGenericTypeDefinition() == typeof(List<>))
{
values[i] = (v as List<pType>).First();
}
UPDATE
I guess it is not the best solution because it does not accept any List type but it is the best I could do:
public static DataTable ListToDataTable<T>(IEnumerable<T> list)
{
Type type = typeof(T);
var properties = type.GetProperties();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
Type propertyType = info.PropertyType;
if (propertyType.IsGenericType | propertyType.GetGenericTypeDefinition() == typeof(Nullable<>) | propertyType.IsEnum)
propertyType = propertyType.GetGenericArguments()[0];
dataTable.Columns.Add(new DataColumn(info.Name, propertyType));
}
foreach (T entity in list)
{
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
var v = properties[i].GetValue(entity);
Type pType = v.GetType().GetGenericArguments().FirstOrDefault();
if (v.GetType().GetGenericTypeDefinition() == typeof(List<>))
{
if(pType == typeof(int))
values[i] = (v as List<int>).First();
else if(pType == typeof(string))
values[i] = (v as List<string>).First();
}
else
{
values[i] = v;
}
}
dataTable.Rows.Add(values);
}
return dataTable;
}
You need something like this:
foreach (PropertyInfo info in properties)
{
if(info.PropertyType == typeof(IEnumerable))
{
dataTable.Columns.Add(new DataColumn(info.Name, info.Cast<object>().First().GetType());
}
else
{
dataTable.Columns.Add(new DataColumn(info.Name, info.PropertyType));
}
}
foreach (T entity in list)
{
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
var v = properties[i].GetValue(entity);
if(v is IEnumerable)
{
values[i] = (v.Cast<object>().First()).First();
}
else
{
values[i] = v;
}
}
dataTable.Rows.Add(values);
}
This works for me. I got it here and modified it a little bit.
public static DataTable ToDataTable<T>(this System.Collections.Generic.List<T> collection, string _sTableName) {
var table = new DataTable(_sTableName);
var type = typeof(T);
var properties = type.GetProperties();
//Create the columns in the DataTable
foreach (var property in properties) {
if (property.PropertyType == typeof(int?)) {
table.Columns.Add(property.Name, typeof(int));
} else if (property.PropertyType == typeof(decimal?)) {
table.Columns.Add(property.Name, typeof(decimal));
} else if (property.PropertyType == typeof(double?)) {
table.Columns.Add(property.Name, typeof(double));
} else if (property.PropertyType == typeof(DateTime?)) {
table.Columns.Add(property.Name, typeof(DateTime));
} else if (property.PropertyType == typeof(Guid?)) {
table.Columns.Add(property.Name, typeof(Guid));
} else if (property.PropertyType == typeof(bool?)) {
table.Columns.Add(property.Name, typeof(bool));
} else {
table.Columns.Add(property.Name, property.PropertyType);
}
}
//Populate the table
foreach (var item in collection) {
var row = table.NewRow();
row.BeginEdit();
foreach (var property in properties) {
row[property.Name] = property.GetValue(item, null) ?? DBNull.Value;
}
row.EndEdit();
table.Rows.Add(row);
}
return table;
}

add dynamic anonymous object into linq groupBy expression

I have following linq expression:
Func<Entity, object> groupQuery = item =>
new { a = item.Attributes["name"], item = item.Attributes["number"] };
var result = target.Collection.Entities.GroupBy(groupQuery).ToList();
But if i don't know, how much columns i will group (for example 3 instead of 2),and names of the Attributes stored in List Names, How should i change my groupQuery object? My first idea was to create dynamic object like this but it don't work
dynamic groupQuery= new ExpandoObject();
IDictionary<string, object> dictionary = (IDictionary<string, object>)groupQuery;
foreach (string str in Names)
{
dictionary.Add(str, str);
}
Instead of returning an object from groupQuery you can return a string. This string will be constructed from properties of objects that you want to group. Depending on the configuration it can be generated in different ways i.e. based on different properties. Here is a code that shows an idea:
public class A
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
}
public enum GroupByuMode
{
GroupBy1,
GroupBy2,
GroupBy3,
}
...
var list = new List<A>();
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
list.Add(new A { Property1 = i.ToString(), Property2 = j.ToString(), Property3 = k.ToString() });
var mode = GroupByuMode.GroupBy1;
Func<A, object> func = a =>
{
if (mode == GroupByuMode.GroupBy1)
return a.Property1;
else if (mode == GroupByuMode.GroupBy2)
return String.Format("{0}_{1}", a.Property1, a.Property2);
else if (mode == GroupByuMode.GroupBy3)
return String.Format("{0}_{1}_{2}", a.Property1, a.Property2, a.Property3);
return null;
};
var res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);
mode = GroupByuMode.GroupBy2;
res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);
It works witch LINQ to Objects as shown above. You have to check if it works with LINQ to Entities or another implementation of LINQ.
answer in question
C# LINQ - How to build Group By clause dynamically
IEnumerable<string> columnsToGroupBy = new[] { Names.First()};
Names.RemoveAt(0);
Names.Aggregate(columnsToGroupBy, (current, query) => current.Concat(new[] {query}));
GroupQuery = r => new NTuple<object>(from column in columnsToGroupBy select r[column]);
///////
using System;
using System.Collections.Generic;
using System.Linq;
namespace WBTCB.AggregationService.Models.Helpers
{
public class NTuple<T> : IEquatable<NTuple<T>>
{
public NTuple(IEnumerable<T> values)
{
Values = values.ToArray();
}
public readonly T[] Values;
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
return true;
if (obj == null)
return false;
return Equals(obj as NTuple<T>);
}
public bool Equals(NTuple<T> other)
{
if (ReferenceEquals(this, other))
return true;
if (other == null)
return false;
var length = Values.Length;
if (length != other.Values.Length)
return false;
for (var i = 0; i < length; ++i)
if (!Equals(Values[i], other.Values[i]))
return false;
return true;
}
public override int GetHashCode()
{
return Values.Aggregate(17, (current, value) => current*37 + (!ReferenceEquals(value, null) ? value.GetHashCode() : 0));
}
}
}

Object To DataView or DataSet or DataTable and back to object

We have a mish-mash app with a legacy module that still uses DataSets, DataViews and DataTables however we have most of the the databases ORMed except the DB for this Module. I was wondering if someone could give me pointers as to how to go about building extensions like
/* generates a dataset called CustomerDS with
DataTable called Customer uses property names as DataColumn name */
var dataset =_customer.AsDataSet();
/* Converts the dataset to required object or
throws exception if its cant convert*/
var customerEntity = _dataset.ToObject<Customer>();
I dont know when we will get time to work on other layers of the app and free it from DataSets. I might sound crazy but its just a thought. I get nightmares when i need to support/bug fix that app.
You can use a reflection for example:
class Program {
public static void Start( string[] args ) {
var john = new Customer {
CustomerID = Guid.NewGuid(),
CustomerName = "John",
CustomerCode = "J-O"
};
var tblJohn = john.ToDataTable();
var clonedJohn = tblJohn.Rows[0].ToDataObject<Customer>();
}
}
[AttributeUsage(AttributeTargets.Property)]
public class DataColumnAttribute : Attribute { }
public class Customer {
[DataColumn]
public Guid CustomerID { get; set; }
[DataColumn]
public string CustomerName { get; set; }
[DataColumn]
public string CustomerCode { get; set; }
}
public static class DataObjectExtensions {
public static T ToDataObject<T>( this DataRow dataRow ) where T : new() {
var dataObject = Activator.CreateInstance<T>();
var tpDataObject = dataObject.GetType();
foreach ( var property in tpDataObject.GetProperties() ) {
var attributes = property.GetCustomAttributes( typeof( DataColumnAttribute ), true );
if ( null != attributes && attributes.Length > 0 ) {
if ( property.CanWrite ) {
DataColumn clm = dataRow.Table.Columns[property.Name];
if ( null != clm ) {
object value = dataRow[clm];
property.SetValue( dataObject, value, null );
}
}
}
}
return dataObject;
}
public static DataTable ToDataTable( this object dataObject ) {
var tpDataObject = dataObject.GetType();
DataTable tbl = new DataTable();
DataRow dataRow = tbl.NewRow();
foreach ( var property in tpDataObject.GetProperties() ) {
var attributes = property.GetCustomAttributes( typeof( DataColumnAttribute ), true );
if ( null != attributes && attributes.Length> 0 ) {
if ( property.CanRead ) {
object value = property.GetValue( dataObject, null );
DataColumn clm = tbl.Columns.Add( property.Name, property.PropertyType );
dataRow[clm] = value;
}
}
}
tbl.Rows.Add( dataRow );
tbl.AcceptChanges();
return tbl;
}
}
You can use this to get object from data table
public static class Extensions
{
public static List<T> ToList<T>(this DataTable table) where T : new()
{
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
List<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)
{
if (property.PropertyType == typeof(System.DayOfWeek))
{
DayOfWeek day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), row[property.Name].ToString());
property.SetValue(item,day,null);
}
else
{
property.SetValue(item, row[property.Name], null);
}
}
return item;
}
}
and use it like this
List<Employee> lst = ds.Tables[0].ToList<Employee>();

Categories

Resources