2009-02-07 51 views
14

Đưa ra một danh sách các đối tượng, tôi cần chuyển đổi nó thành tập dữ liệu trong đó mỗi mục trong danh sách được biểu thị bằng một hàng và mỗi thuộc tính là một cột trong hàng. Số liệu này sau đó sẽ được chuyển đến một hàm Aspose.Cells để tạo tài liệu Excel dưới dạng báo cáo.Làm cách nào để chuyển đổi Danh sách <T> thành Tập dữ liệu?

Nói rằng tôi có như sau:

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

Với một danh sách hồ sơ, làm thế nào để biến nó thành một DataSet như sau:

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

Tại thời điểm điều duy nhất tôi có thể nghĩ đến như sau:

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

Nhưng cách này khiến tôi nghĩ phải có cách tốt hơn từ ít nhất là nếu các thuộc tính mới được thêm vào Record thì chúng sẽ không hiển thị trong DataSet ... nhưng đồng thời nó cho phép tôi kiểm soát thứ tự mỗi thuộc tính được thêm vào hàng.

Có ai biết cách tốt hơn để làm điều này không?

Trả lời

27

Bạn có thể làm điều đó thông qua phản chiếu và generics, kiểm tra các thuộc tính của loại cơ bản.

xem xét phương pháp này mở rộng mà tôi sử dụng:

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

Vâng, cộng đồng đã nói nên tôi sẽ bỏ phiếu cho câu trả lời này mặc dù tôi sẽ không thể sử dụng nó cho mục đích của mình vì tôi muốn có thể kiểm soát thứ tự của các tham số. Nhưng tôi chắc chắn sẽ giữ giải pháp này trong đầu ... – mezoid

+2

Này, tôi vừa thử nghiệm phần mở rộng của bạn và thấy rằng nếu bạn muốn kiểm soát thứ tự các cột xuất hiện trong datatable thì bạn cần khai báo chúng theo thứ tự bạn muốn chúng trong đối tượng của loại T mà bạn chuyển đến phần mở rộng. Thật tuyệt vời! – mezoid

1

Ngoài việc sử dụng thêm Reflection để xác định thuộc tính của lớp Record để xử lý thêm thuộc tính mới, điều đó khá nhiều.

+0

Bạn đang có lẽ đúng ... mặc dù nó không phải là điều tôi muốn nghe. Tôi đoán là tôi cần phải cải thiện kiến ​​thức của mình về DataSets hoặc một ai đó ở Microsoft cần phải nghĩ ra một cách tốt hơn. – mezoid

0

Tôi đã viết một thư viện nhỏ bản thân mình để hoàn thành nhiệm vụ này. Nó chỉ sử dụng sự phản chiếu cho lần đầu tiên một kiểu đối tượng được dịch sang một datatable. Nó phát ra một phương thức sẽ làm tất cả công việc dịch một kiểu đối tượng.

Tốc độ nhanh của nó. Bạn có thể tìm thấy nó ở đây: ModelShredder on GoogleCode

0

Tôi đã thực hiện một số thay đổi đối với phương pháp tiện ích CMS 'để xử lý trường hợp khi List chứa các thành phần nguyên thủy hoặc String. Trong trường hợp đó, kết quả DataTable sẽ chỉ có một Column với một cho mỗi giá trị trong danh sách.

Lúc đầu, tôi nghĩ đến việc bao gồm tất cả các loại giá trị (không chỉ các kiểu nguyên thủy) mà tôi không muốn Cấu trúc (là các loại giá trị) được đưa vào.

Sự thay đổi này xuất phát từ nhu cầu chuyển đổi List(Of Long) hoặc List<long> thành DataTable để sử dụng nó dưới dạng tham số bảng giá trị trong thủ tục lưu trữ MS SQL 2008.

Tôi rất tiếc vì mã của tôi nằm trong VB mặc dù câu hỏi này được gắn thẻ ; dự án của tôi là trong VB (KHÔNG lựa chọn của tôi) và nó không phải là khó khăn để áp dụng những thay đổi trong 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

Tôi tìm thấy mã này trên diễn đàn của Microsoft. Đây là một trong những cách dễ nhất, dễ hiểu và dễ sử dụng. Điều này đã giúp tôi tiết kiệm thời gian. Tôi đã tùy chỉnh phương thức này dưới dạng tiện ích mở rộng mà không có bất kỳ thay đổi nào đối với triển khai thực tế. Dưới đây là mã. nó không đòi hỏi nhiều lời giải thích.

Bạn có thể sử dụng hai chức năng chữ ký với cùng thực hiện

1) public static DataSet ToDataSetFromObject (điều này đối tượng dsCollection)

2) public static DataSet ToDataSetFromArrayOfObject (điều này object [] arrCollection). Tôi sẽ sử dụng cái này trong ví dụ dưới đây.

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

Để sử dụng phần mở rộng này trong mã

Country[] objArrayCountry = null; 
objArrayCountry = ....;// populate your array 
if ((objArrayCountry != null)) { 
    dataset = objArrayCountry.ToDataSetFromArrayOfObject(); 
} 
Các vấn đề liên quan