I have a Generic list of Objects. Each object has 9 string properties. I want to turn that list into a dataset that i can pass to a datagridview......Whats the best way to go about doing this?
问题:
回答1:
Have you tried binding the list to the datagridview directly? If not, try that first because it will save you lots of pain. If you have tried it already, please tell us what went wrong so we can better advise you. Data binding gives you different behaviour depending on what interfaces your data object implements. For example, if your data object only implements IEnumerable
(e.g. List
), you will get very basic one-way binding, but if it implements IBindingList
as well (e.g. BindingList
, DataView
), then you get two-way binding.
回答2:
I apologize for putting an answer up to this question, but I figured it would be the easiest way to view my final code. It includes fixes for nullable types and null values :-)
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;
}
回答3:
There is a bug with Lee's extension code above, you need to add the newly filled row to the table t when iterating throught the items in the list.
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())
{
t.Columns.Add(propInfo.Name, propInfo.PropertyType);
}
//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);
}
//This line was missing:
t.Rows.Add(row);
}
return ds;
}
回答4:
You could create an extension method to add all property values through reflection:
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())
{
t.Columns.Add(propInfo.Name, propInfo.PropertyType);
}
//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);
}
}
return ds;
}
回答5:
You may want to check out
http://www.codeproject.com/KB/vb/List2DataSet.aspx
Gives a few different approaches.
回答6:
Brute force code to answer your question:
DataTable dt = new DataTable();
//for each of your properties
dt.Columns.Add("PropertyOne", typeof(string));
foreach(Entity entity in entities)
{
DataRow row = dt.NewRow();
//foreach of your properties
row["PropertyOne"] = entity.PropertyOne;
dt.Rows.Add(row);
}
DataSet ds = new DataSet();
ds.Tables.Add(dt);
return ds;
Now for the actual question. Why would you want to do this? As mentioned earlier, you can bind directly to an object list. Maybe a reporting tool that only takes datasets?
回答7:
I've written a small library myself to accomplish this task. It uses reflection only for the first time an object type is to be translated to a datatable. It emits a method that will do all the work translating an object type.
Its the fastest solution i know (thats why i developed it :-) ). You can find it here: ModelShredder on GoogleCode
Currently it is only supporting translation to a DataTable. As you phrased your question, this should be sufficient. Support for DataSets (think of a simple reverse ORM) is already developed, it will be released in two weaks when i am back from vacation :-)
回答8:
I have slightly modified the accepted answer by handling value types. I came across this when trying to do the following and because GetProperties() is zero length for value types I was getting an empty dataset. I know this is not the use case for the OP but thought I'd post this change in case anyone else came across the same thing.
Enumerable.Range(1, 10).ToList().ToDataSet();
public static DataSet ToDataSet<T>(this IList<T> list)
{
var elementType = typeof(T);
var ds = new DataSet();
var t = new DataTable();
ds.Tables.Add(t);
if (elementType.IsValueType)
{
var colType = Nullable.GetUnderlyingType(elementType) ?? elementType;
t.Columns.Add(elementType.Name, colType);
} else
{
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
var 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 (var item in list)
{
var row = t.NewRow();
if (elementType.IsValueType)
{
row[elementType.Name] = item;
}
else
{
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
}
t.Rows.Add(row);
}
return ds;
}
回答9:
One option would be to use a System.ComponenetModel.BindingList rather than a list.
This allows you to use it directly within a DataGridView. And unlike a normal System.Collections.Generic.List updates the DataGridView on changes.
回答10:
I found this code on Microsoft forum. This is so far one of easiest way, easy to understand and use. This has saved me hours , I have customized it as extension method without any change to actual method. Below is the code. it doesn't require much explanation.
You can use two function signature with same implementation
1) public static DataSet ToDataSetFromObject(this object dsCollection)
2) public static DataSet ToDataSetFromArrayOfObject( this object[] arrCollection) . I 'll be using this one for example.
// <summary>
// Serialize Object to XML and then read it into a DataSet:
// </summary>
// <param name="arrCollection">Array of object</param>
// <returns>dataset</returns>
public static DataSet ToDataSetFromArrayOfObject( this object[] arrCollection)
{
DataSet ds = new DataSet();
try {
XmlSerializer serializer = new XmlSerializer(arrCollection.GetType);
System.IO.StringWriter sw = new System.IO.StringWriter();
serializer.Serialize(sw, dsCollection);
System.IO.StringReader reader = new System.IO.StringReader(sw.ToString());
ds.ReadXml(reader);
} catch (Exception ex) {
throw (new Exception("Error While Converting Array of Object to Dataset."));
}
return ds;
}
To use this extension in code
Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}