2012-03-30 40 views
6

Tôi đang sử dụng .NET 3.5 và cần chuyển đổi kết quả mới dưới đây thành một DataTable. Có cái gì được xây dựng trong này hay bất cứ ai biết về một phương pháp có thể làm điều này?Chuyển đổi chọn mới thành DataTable?

var contentList = (from item in this.GetData().Cast<IContent>() 
        select new 
        { 
         Title = item.GetMetaData("Title"), 
         Street = item.GetMetaData("Street"), 
         City = item.GetMetaData("City"), 
         Country = item.GetMetaData("Country") 
        }); 
+0

Bạn đang làm gì mà bạn cần một DataTable như là kết quả? – dwerner

+0

Tôi đang cố gắng xuất sang CSV và đã có phương pháp có thể xuất DataTable/Đặt thành CSV. – TruMan1

+1

Tôi nghĩ rằng bạn đang tìm kiếm một ngôn ngữ lập trình động trong một (chủ yếu) được đánh máy tĩnh. Nếu bạn đang rất gắn bó với những DataTable để csv xuất khẩu thói quen, sau đó tôi sợ con đường của bạn có thể là một tread của chỉ có bạn. Các đối tượng ẩn danh là một tính năng ngôn ngữ khá mới, và DataRow/DataTable/DataSet không được thiết kế với chúng. – dwerner

Trả lời

7

Dễ dàng và đơn giản điều cần làm là sử dụng sự phản chiếu:

var records = (from item in this.GetData().Cast<IContent>() 
          select new 
          { 
           Title = "1", 
           Street = "2", 
           City = "3", 
           Country = "4" 
          }); 
var firstRecord = records.First(); 
if (firstRecord == null) 
    return; 

var infos = firstRecord.GetType().GetProperties(); 
DataTable table = new DataTable(); 
foreach (var info in infos) { 
    DataColumn column = new DataColumn(info.Name, info.PropertyType); 
    table.Columns.Add(column); 
} 

foreach (var record in records) { 
    DataRow row = table.NewRow(); 
    for (int i = 0; i < table.Columns.Count; i++) 
     row[i] = infos[i].GetValue(record); 
    table.Rows.Add(row); 
} 

Mã có thể không hoạt động trước nhưng nên cung cấp cho bạn ý tưởng chung. Đầu tiên, bạn nhận được propertyInfos từ kiểu ẩn danh và sử dụng siêu dữ liệu này để tạo lược đồ có thể đặt (cột điền). Sau đó, bạn sử dụng những infos đó để lấy các giá trị từ mọi đối tượng.

+0

Nhưng Reflection sẽ đạt hiệu suất mỗi khi mã chạy.Tôi muốn chỉ định các thuộc tính theo cách thủ công trong mã. – Ramesh

+1

Vâng, vì OP có 30 thuộc tính trở lên và có thể có hơn 1 trường hợp sử dụng, nên sẽ phản tác dụng để chỉ định thủ công. Ngoài ra, có những thủ thuật để làm cho sự phản chiếu hiệu quả hơn (như sử dụng sự phản chiếu chỉ một lần và tạo ra phương thức ánh xạ động lưu trong bộ nhớ cho việc sử dụng chuyển đổi đối tượng trong tương lai hoặc thư viện fastreflection). –

+0

Nhìn vào giải pháp chung của tôi mà không sử dụng Reflection thay vì sử dụng cây biểu thức. Vay một số mã từ giải pháp của bạn – Ramesh

0

Có một số CopyToDataTable extension method làm điều đó cho bạn. Nó sống ở System.Data.DataSetExtensions.dll

+0

Tôi đã hy vọng tôi có thể sử dụng điều này, nhưng tôi nhận được một lỗi biên dịch: Lỗi Loại 'AnonymousType # 1' không thể được sử dụng làm loại tham số 'T' trong kiểu generic hoặc phương thức 'System.Data.DataTableExtensions.CopyToDataTable (System.Collections.Generic.IEnumerable )'. Không có chuyển đổi tham chiếu ngầm định từ 'AnonymousType # 1' thành 'System.Data.DataRow'. – TruMan1

+0

Vâng, đây không phải là một phương pháp hữu ích để sao chép từ các đối tượng, ẩn danh hay cách khác, trừ khi chúng xuống từ DataRow. – dwerner

0

Hãy thử điều này:

// Create your datatable. 

DataTable dt = new DataTable(); 
dt.Columns.Add("Title", typeof(string)); 
dt.Columns.Add("Street", typeof(double)); 


// get a list of object arrays corresponding 
// to the objects listed in the columns 
// in the datatable above. 
var result = from item in in this.GetData().Cast<IContent>()    
      select dt.LoadDataRow(
       new object[] { Title = item.GetMetaData("Title"), 
           Street = item.GetMetaData("Street"), 
       }, 
       false); 


// the end result will be a set of DataRow objects that have been 
// loaded into the DataTable. 

Original Điều cho mẫu mã: Converting Anonymous type generated by LINQ to a DataTable type

EDIT: Generic Mã giả:

void LinqToDatatable(string[] columns, Type[] datatypes, linqSource) 
{ 
    for loop 
    { 
     dt.columns.add(columns[i], datatypes[i]); 
    } 

//Still thinking how to make this generic.. 
var result = from item in in this.GetData().Cast<IContent>()    
      select dt.LoadDataRow(
       new object[] { string[0] = item.GetMetaData[string[0]], 
           string[1] = item.GetMetaData[srring[1] 
       }, 
       false); 


} 
+0

Tôi thực sự có hơn 30 thuộc tính và muốn điều này là chung chung. Có cách nào khác ngoài việc mã hóa cứng các cột không? Tôi cũng có thể tạo ra một lớp thực sự thay vì sử dụng một lớp ẩn danh. – TruMan1

+0

Kiểm tra chỉnh sửa của tôi. Vẫn đang suy nghĩ về cách làm cho phần thứ hai chung chung. –

0

Bạn có thể chuyển đổi kết quả danh sách của bạn để DataTable bởi các chức năng dưới đây

public static DataTable ToDataTable<T>(IEnumerable<T> values) 
    { 
     DataTable table = new DataTable(); 

     foreach (T value in values) 
     { 
      if (table.Columns.Count == 0) 
      { 
       foreach (var p in value.GetType().GetProperties()) 
       { 
        table.Columns.Add(p.Name); 
       } 
      } 

      DataRow dr = table.NewRow(); 
      foreach (var p in value.GetType().GetProperties()) 
      { 
       dr[p.Name] = p.GetValue(value, null) + ""; 

      } 
      table.Rows.Add(dr); 
     } 

     return table; 
    } 
3

Dưới đây là một giải pháp chung chung mà không Phản ánh trên các thuộc tính. Có phương thức tiện ích mở rộng như bên dưới

public static DataTable ConvertToDataTable<TSource>(this IEnumerable<TSource> 
        records, params Expression<Func<TSource, object>>[] columns) 
    { 
     var firstRecord = records.First(); 
     if (firstRecord == null) 
      return null; 

     DataTable table = new DataTable(); 

     List<Func<TSource, object>> functions = new List<Func<TSource, object>>(); 
     foreach (var col in columns) 
     { 
      DataColumn column = new DataColumn(); 
      column.Caption = (col.Body as MemberExpression).Member.Name; 
      var function = col.Compile(); 
      column.DataType = function(firstRecord).GetType(); 
      functions.Add(function); 
      table.Columns.Add(column); 
     } 

     foreach (var record in records) 
     { 
      DataRow row = table.NewRow(); 
      int i = 0; 
      foreach (var function in functions) 
      { 
       row[i++] = function((record)); 
      } 
      table.Rows.Add(row); 
     } 
     return table; 
    } 

Và gọi cùng sử dụng thông số nơi tên cột theo thứ tự bạn muốn.

var table = records.ConvertToDataTable(
             item => item.Title, 
             item => item.Street, 
             item => item.City 
            ); 
+0

Biến tôi dường như không bao giờ thay đổi? – NetMage

0
public static DataTable ListToDataTable<T>(this IList<T> data) 
     { 
      DataTable dt = new DataTable(); 
      PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T)); 
      for (int i = 0; i < props.Count; i++) 
      { 
       PropertyDescriptor prop = props[i]; 
       dt.Columns.Add(prop.Name, prop.PropertyType); 
      } 
      object[] values = new object[props.Count]; 
      foreach (T t in data) 
      { 
       for (int i = 0; i < values.Length; i++) 
       { 
        values[i] = props[i].GetValue(t); 
       } 
       dt.Rows.Add(values); 
      } 
      return dt; 
     } 

Sau khi bạn làm chọn của bạn mới có thể để .ToList().ListToDataTable(). Điều này sử dụng sự phản ánh ComponentModel và nhanh hơn SystemReflection (theroetically).

Các vấn đề liên quan