2009-02-07 4 views
14

개체 목록이 주어지면 목록의 각 항목이 행으로 표시되고 각 속성이 행의 열인 데이터 집합으로 변환해야합니다. 이 데이터 집합은 Aspose.Cells 함수에 전달되어 Excel 문서를 보고서로 만듭니다. 순간 내가 생각할 수있는 유일한 것은에서List <T>을 DataSet으로 변환하려면 어떻게해야합니까?

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

을 다음과 같이리스트 기록을 감안할 때

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

가, 어떻게 데이터 집합으로 변환 않습니다

내가 다음 말해봐

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

그러나이 방법을 사용하면 더 나은 방법이 있어야한다고 생각합니다. 최소한 새로운 속성이 Record에 추가되면 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

안녕하세요, 방금 확장 기능을 테스트 한 결과 주문을 제어하려면 열이 데이터 테이블에 표시되고 다음 순서로 선언해야한다는 사실을 발견했습니다. 확장자에 전달하는 T 유형의 객체에서 원한다. 멋지다! – mezoid

1

Reflection을 추가로 사용하는 것 이외에도 새로운 속성을 추가 할 때 Record 클래스의 속성을 결정하는 것은 별개입니다.

+0

이 확장을 사용합니다. 데이터 세트에 대한 나의 지식을 향상 시키거나 Microsoft에서 더 나은 방법을 생각해야 할 필요가 있습니다. – mezoid

0

:

내가 사용이 확장 방법을 고려하십시오. 객체 유형이 데이터 테이블로 처음 변환 될 때만 리플렉션을 사용합니다. 객체 유형을 변환하는 모든 작업을 수행하는 메소드를 내 보냅니다.

빠른 속도. 당신은 여기에서 그것을 찾을 수 있습니다 : ModelShredder on GoogleCode

0

List이 원시 또는 String 요소를 포함 할 때 대소 문자를 처리하기 위해 CMS의 확장 방법을 약간 변경했습니다. 이 경우 결과물 인 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) 공공 정적 데이터 집합 ToDataSetFromObject (이 객체 dsCollection)

2) 공공 정적 데이터 집합 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(); 
} 
관련 문제