2009-08-07 53 views
15

Tôi có danh sách Đối tượng chung. Mỗi đối tượng có 9 thuộc tính chuỗi. Tôi muốn biến danh sách đó thành một tập dữ liệu mà tôi có thể chuyển đến một datagridview ...... Whats cách tốt nhất để làm gì?Chuyển danh sách chung thành tập dữ liệu trong C#

+1

thể trùng lặp của [Làm thế nào để chuyển đổi một danh sách vào một DataSet?] (Http://stackoverflow.com/questions/523153/how- do-i-transform-a-listt-into-a-dataset) –

Trả lời

12

Bạn đã thử ràng buộc danh sách trực tiếp vào chế độ xem dữ liệu chưa? Nếu không, hãy thử điều đó trước vì nó sẽ giúp bạn tiết kiệm rất nhiều đau đớn. Nếu bạn đã thử nó, xin vui lòng cho chúng tôi biết những gì đã xảy ra để chúng tôi có thể tư vấn cho bạn tốt hơn. Ràng buộc dữ liệu cung cấp cho bạn hành vi khác nhau tùy thuộc vào giao diện mà đối tượng dữ liệu của bạn thực hiện. Ví dụ: nếu đối tượng dữ liệu của bạn chỉ triển khai IEnumerable (ví dụ: List), bạn sẽ nhận được ràng buộc một chiều rất cơ bản, nhưng nếu nó cũng thực hiện IBindingList (ví dụ: BindingList, DataView), thì bạn sẽ nhận được liên kết hai chiều.

+0

ràng buộc trực tiếp sẽ không hoạt động ra rất thường xuyên: Nó là chậm, và phân loại là một nỗi đau. Nếu nó chỉ lên đến 1000rows tốt của nó, cho tất cả mọi thứ khác tôi khuyên bạn nên một trình dịch dataTable nhanh như ModelShredder của tôi (xem bên dưới) –

+1

Phân loại là một nỗi đau. Vì vậy, là lọc. Vì vậy, là chỉnh sửa. Có thể xây dựng một đối tượng hỗ trợ tất cả các trường hợp sử dụng mà DataTable làm, nhưng nó không phải là một số lượng nhỏ công việc - đặc biệt so với chỉ sao chép dữ liệu vào một DataTable. –

+0

yup, đó là lý do tại sao tôi đã viết modelshredder. Tôi sợ rằng chỉnh sửa là tất nhiên không được hỗ trợ, nhưng tôi không thấy điều này như là một vấn đề bởi vì tôi nghĩ rằng chỉnh sửa dữ liệu trong một bảng nên tránh cho những lý do nêu trên. Luôn luôn có excel :-) –

0

Một tùy chọn sẽ là sử dụng System.ComponenetModel.BindingList thay vì danh sách.

Điều này cho phép bạn sử dụng trực tiếp trong DataGridView. Và không giống như một System.Collections.Generic.List bình thường cập nhật DataGridView về các thay đổi.

2

đang brute force để trả lời câu hỏi của bạn:

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; 

Bây giờ cho câu hỏi thực tế. Tại sao bạn muốn làm điều này? Như đã đề cập trước đó, bạn có thể liên kết trực tiếp với một danh sách đối tượng. Có thể một công cụ báo cáo chỉ lấy bộ dữ liệu?

+0

Một câu trả lời cho lý do tại sao một người muốn làm điều này, dù sao thì tôi cũng là WCF. Dịch vụ thực sự không thích đặt generics trên dây. Tôi đang viết một số mã để trả lại trang và đặt hàng kết quả từ một kho lưu trữ và tôi đang đối phó với một Số liệu cho bây giờ ... Một lý do là các lĩnh vực được trả lại không phải lúc nào cũng giống nhau ... Tôi không chắc chắn nếu điều đó sẽ bay mặc dù, nó có thể cần DTO, có nghĩa là tôi có vấn đề khác, nhưng tôi digress :-) –

2

Tôi đã tự viết một thư viện 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.

Giải pháp nhanh nhất tôi biết (đó là lý do tôi phát triển nó :-)). Bạn có thể tìm thấy tại đây: ModelShredder trên GoogleCode

Hiện tại, dịch vụ này chỉ hỗ trợ dịch sang DataTable. Khi bạn phrased câu hỏi của bạn, điều này là đủ. Hỗ trợ cho DataSets (suy nghĩ của một ORM đảo ngược đơn giản) đã được phát triển, nó sẽ được phát hành trong hai yếu khi tôi trở về từ kỳ nghỉ :-)

4

Bạn có thể tạo một phương pháp mở rộng để thêm tất cả các giá trị thuộc tính thông qua phản ánh:

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; 
} 
+0

Cảm ơn mã, một vấn đề nhỏ mặc dù, Nullable loại bom ... Tôi sẽ cố gắng sửa đổi nó để thích ứng với họ, nhưng tôi không phải là một chuyên gia phản chiếu. Nếu tôi nhận được một cái gì đó làm việc ra, tôi sẽ gửi một bản cập nhật :-) –

+0

Ok, tôi đã phải thực hiện hai thay đổi, một cho các loại Nullable và một cho giá trị null ... t.Columns.Add (propInfo.Name, propInfo.PropertyType); trở thành Loại ColType = Nullable.GetUnderlyingType (propInfo.PropertyType) ?? propInfo.PropertyType; t.Columns.Add (propInfo.Name, ColType); và hàng [propInfo.Name] = propInfo.GetValue (mục, null); trở thành hàng [propInfo.Name] = propInfo.GetValue (mục, null) ?? DBNull.Value; Cảm ơn bạn đã nhập mã :-) –

11

Có lỗi với mã mở rộng của Lee ở trên, bạn cần phải thêm hàng mới được điền vào bảng t khi lặp qua các mục trong danh sách.

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; 

}

55

Tôi xin lỗi vì đưa ra câu trả lời đến câu hỏi này, nhưng tôi figured nó sẽ là cách dễ nhất để xem mã cuối cùng của tôi. Nó bao gồm các bản sửa lỗi cho các loại nullable và giá trị null :-)

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; 
    } 
+2

Tuyệt vời! Điều này vừa cứu mạng tôi trong một dự án tôi đang làm ngay bây giờ! – Konamiman

+1

Chỉ cần lưu tôi rất nhiều thời gian. Cảm ơn – Willem

+2

Cảm ơn vì điều này, đoạn trích tuyệt vời :) Chỉ cần một bugfix, tôi đã thêm nếu (list.Count()!= 0) trước khi foreach, bởi vì, nếu danh sách bạn không muốn chuyển đổi là trống, mã sẽ ném một ngoại lệ. –

1

Tôi đã sửa đổi một chút câu trả lời bằng cách xử lý các loại giá trị. Tôi đi qua điều này khi cố gắng làm như sau và bởi vì GetProperties() là không có chiều dài cho các loại giá trị tôi đã nhận được một tập dữ liệu rỗng.Tôi biết đây không phải là trường hợp sử dụng cho OP nhưng tôi nghĩ rằng tôi sẽ đăng thay đổi này trong trường hợp bất kỳ ai khác gặp phải điều tương tự.

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

tôi tìm thấy mã này trên Microsoft diễn đàn. Đây là một trong những cách dễ nhất, dễ hiểu và dễ sử dụng. Điều này đã tiết kiệm cho tôi giờ, tôi đã tùy chỉnh nó như là phương pháp mở rộng mà không có bất kỳ thay đổi phương pháp 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 tượng này dsCollection)

2) public static DataSet ToDataSetFromArrayOfObject (đối tượng này [] arrCollection). Tôi sẽ sử dụng ví dụ nà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