2009-02-07 2 views
14

Учитывая список объектов, мне нужно преобразовать их в набор данных, где каждый элемент в списке представлен строкой, а каждое свойство является столбцом в строке. Затем этот DataSet будет передан функции Aspose.Cells, чтобы создать документ Excel в качестве отчета.Как преобразовать список <T> в DataSet?

Скажем, у меня есть следующие:

public class Record 
{ 
    public int ID { get; set; } 
    public bool Status { get; set; } 
    public string Message { get; set; } 
} 

Учитывая список записей, как я превратить его в DataSet следующим образом:

ID Status Message 
1 true "message" 
2 false "message2" 
3 true "message3" 
... 

На данный момент единственное, что я могу думать о заключается в следующем:

DataSet ds = new DataSet 
ds.Tables.Add(); 
ds.Tables[0].Add("ID", typeof(int));  
ds.Tables[0].Add("Status", typeof(bool)); 
ds.Tables[0].Add("Message", typeof(string)); 

foreach(Record record in records) 
{ 
    ds.Tables[0].Rows.Add(record.ID, record.Status, record.Message); 
} 

Но этот путь оставляет мне мнение, что должен быть лучший способ, поскольку на в самом деле, если новые свойства добавляются в запись, они не будут отображаться в DataSet ... но в то же время это позволяет мне управлять порядком, в которое каждое свойство добавляется в строку.

Кто-нибудь знает, как лучше это сделать?

ответ

27

Вы можете сделать это с помощью отражений и дженериков, проверяя свойства базового типа.

Рассмотрим этот метод расширения, который я использую:

public static DataTable ToDataTable<T>(this IEnumerable<T> collection) 
    { 
     DataTable dt = new DataTable("DataTable"); 
     Type t = typeof(T); 
     PropertyInfo[] pia = t.GetProperties(); 

     //Inspect the properties and create the columns in the DataTable 
     foreach (PropertyInfo pi in pia) 
     { 
      Type ColumnType = pi.PropertyType; 
      if ((ColumnType.IsGenericType)) 
      { 
       ColumnType = ColumnType.GetGenericArguments()[0]; 
      } 
      dt.Columns.Add(pi.Name, ColumnType); 
     } 

     //Populate the data table 
     foreach (T item in collection) 
     { 
      DataRow dr = dt.NewRow(); 
      dr.BeginEdit(); 
      foreach (PropertyInfo pi in pia) 
      { 
       if (pi.GetValue(item, null) != null) 
       { 
        dr[pi.Name] = pi.GetValue(item, null); 
       } 
      } 
      dr.EndEdit(); 
      dt.Rows.Add(dr); 
     } 
     return dt; 
    } 
+0

Ну, сообщество высказалось, поэтому я проголосую за этот ответ, хотя я не смогу использовать его для своих целей, так как хочу контролировать порядок параметров. Но я обязательно буду учитывать это решение ... – mezoid

+2

Эй, я только что протестировал ваше расширение и обнаружил, что если вы хотите контролировать порядок появления столбцов в datatable, тогда вам нужно объявить их в том порядке, в котором вы хотите, чтобы они в объекте типа T перешли к расширению. Это потрясающе! – mezoid

1

Помимо дополнительного использования Reflection, чтобы определить свойства класса Record, чтобы позаботиться о добавлении новых свойств, это в значительной степени.

+0

Вы, вероятно, правы ... хотя его не то, что я хотел услышать. Думаю, мне нужно улучшить свои знания DataSets, или кто-то из Microsoft должен думать о лучшем способе. – mezoid

0

Я написал небольшую библиотеку себя для выполнения этой задачи. Он использует отражение только в первый раз, когда тип объекта должен быть переведен в datatable. Он испускает метод, который будет выполнять всю работу, переводящую тип объекта.

Его пылающий быстрый. Вы можете найти его здесь: ModelShredder on GoogleCode

0

Я сделал некоторые изменения в метод расширения CMS»для обработки случая, когда List содержит примитивный или String элементов. В этом случае итоговый DataTable будет иметь только один Column с для каждого из значений в списке.

Сначала я подумал о включении всех типов значений (не только примитивных типов), но я не хотел включать Структуры (которые являются типами значений).

Это изменение возникла из моей потребности в преобразовании List(Of Long) или List<long>, в DataTable, чтобы использовать его в качестве таблицы многозначного параметра в MS SQL 2008 хранимой процедуры.

Прошу прощения, мой код находится в VB, хотя этот вопрос отмечен ; мой проект находится в VB (не мой выбор), и не должно быть сложно применить изменения в C#.

Imports System.Runtime.CompilerServices 
Imports System.Reflection 

Module Extensions 

    <Extension()> 
    Public Function ToDataTable(Of T)(ByVal collection As IEnumerable(Of T)) As DataTable 
     Dim dt As DataTable = New DataTable("DataTable") 
     Dim type As Type = GetType(T) 
     Dim pia() As PropertyInfo = type.GetProperties() 

     ' For a collection of primitive types create a 1 column DataTable 
     If type.IsPrimitive OrElse type.Equals(GetType(String)) Then 
      dt.Columns.Add("Column", type) 
     Else 
      ' Inspect the properties and create the column in the DataTable 
      For Each pi As PropertyInfo In pia 
       Dim ColumnType As Type = pi.PropertyType 
       If ColumnType.IsGenericType Then 
        ColumnType = ColumnType.GetGenericArguments()(0) 
       End If 
       dt.Columns.Add(pi.Name, ColumnType) 
      Next 

     End If 

     ' Populate the data table 
     For Each item As T In collection 
      Dim dr As DataRow = dt.NewRow() 
      dr.BeginEdit() 
      ' Set item as the value for the lone column on each row 
      If type.IsPrimitive OrElse type.Equals(GetType(String)) Then 
       dr("Column") = item 
      Else 
       For Each pi As PropertyInfo In pia 
        If pi.GetValue(item, Nothing) <> Nothing Then 
         dr(pi.Name) = pi.GetValue(item, Nothing) 
        End If 
       Next 
      End If 
      dr.EndEdit() 
      dt.Rows.Add(dr) 
     Next 
     Return dt 
    End Function 

End Module 
0

Этот код был найден на форуме Microsoft. Это пока что один из самых простых способов, который легко понять и использовать. Это спасло меня. Я настроил это как метод расширения без каких-либо изменений в фактической реализации. Ниже приведен код. это не требует большого объяснения.

Вы можете использовать две функции подписи с той же реализации

1) общественный статический DataSet ToDataSetFromObject (этот объект dsCollection)

2) общественный статический DataSet ToDataSetFromArrayOfObject (это объект [] arrCollection). Я буду использовать этот пример ниже.

// <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; 
} 

Чтобы использовать это расширение в коде

Country[] objArrayCountry = null; 
objArrayCountry = ....;// populate your array 
if ((objArrayCountry != null)) { 
    dataset = objArrayCountry.ToDataSetFromArrayOfObject(); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^