2013-08-25 115 views
5

Tôi cần lưu trữ dữ liệu được trả về từ truy vấn LINQ to Entities (bên dưới) vào DataTable để tôi có thể sử dụng nó làm nguồn dữ liệu cho DataGridView, làm cách nào để thực hiện điều đó?Truy vấn LINQ to Entities vào DataTable

Trong trường hợp này, tôi đang sử dụng LINQ to Entities để truy vấn mô hình khái niệm khung thực thể, vì vậy db là một lớp kế thừa từ System.Data.Entity.DbContext.

using (TccContext db = new TccContext()) 
{ 
    var query = from vendedor in db.Vendedores.AsEnumerable() 
       where vendedor.codigo == Convert.ToInt32(textBoxPesquisa.Text) 
       select vendedor; 
    // I'd like to do something like DataTable dt = query; 
} 

Tôi đã cố gắng thực hiện điều này (bên dưới), nhưng nó ném ngoại lệ trong khi thực thi [1].

using (TccContext db = new TccContext()) 
{ 
    IEnumerable<DataRow> query = (IEnumerable<DataRow>)(from vendedor in db.Vendedores.AsEnumerable() 
                 where vendedor.codigo == Convert.ToInt32(textBoxPesquisa.Text) 
                 select vendedor); 

    using (DataTable dt = query.CopyToDataTable<DataRow>()) 
    { 
     this.dataGridViewProcura.Rows.Add(
      dt.Rows[0][0], // Código 
      dt.Rows[0][1], // Nome 
      dt.Rows[0][2]); // Venda Mensal 
    } 
} 

[1]: Ngoại lệ: InvalidCastException

Unable to cast object of type 'WhereEnumerableIterator`1[Projeto_TCC.Models.Vendedor]' to type 'System.Collections.Generic.IEnumerable`1[System.Data.DataRow]'. 

Cảm ơn trước

Trả lời

2

Có một điều quan trọng ở đây, bạn sẽ được đúc truy vấn LINQ của bạn để (IEnumerable<DataRow>) khi bạn đang chọn vendedor, vì vậy tôi giả định rằng người kiểm duyệt là một phiên bản của Vendedor, do đó truy vấn của bạn sẽ trả về một IEnumerable<Vendedor>

Điều đó sẽ giải quyết vấn đề của bạn, nhưng ngoài ra, bạn có thể thử sử dụng DataTable được tạo ra làm DataSource cho DataGridView của bạn không? Nó sẽ giống như thế này:

var query = (from vendedor in db.Vendedores.AsEnumerable() 
        where vendedor.codigo == Convert.ToInt32(textBoxPesquisa.Text) 
        select vendedor); 
var dt = query.CopyToDataTable<Vendedor>(); 
this.dataGridViewProcura.DataSource = dt; 

Hy vọng tôi có thể giúp!

EDIT

Là một bên (và rất cá nhân) lưu ý, bạn có thể thử sử dụng lambdas vào lựa chọn của bạn, họ trông đẹp hơn :)

var pesquisa = Convert.ToInt32(textBoxPesquisa.Text); 
var query = db.Vendedores.Where(vendedor => vendedor.codigo == pesquisa); 

var dt = query.CopyToDataTable<Vendedor>(); 
this.dataGridViewProcura.DataSource = dt; 

Rất nhiều bụi, không bạn nghĩ sao?

EDIT 2 Tôi vừa mới nhận ra những gì bạn nói trên CopyToDataTable bị cho DataRow chỉ, vì vậy cuối cùng (phải thừa nhận là không quá sạch) giải pháp sẽ được để bắt chước logic trên helper?

public DataTable CopyGenericToDataTable<T>(this IEnumerable<T> items) 
{ 
    var properties = typeof(T).GetProperties(); 
    var result = new DataTable(); 

    //Build the columns 
    foreach (var prop in properties) { 
     result.Columns.Add(prop.Name, prop.PropertyType); 
    } 

    //Fill the DataTable 
    foreach(var item in items){ 
     var row = result.NewRow(); 

     foreach (var prop in properties) { 
      var itemValue = prop.GetValue(item, new object[] {}); 
      row[prop.Name] = itemValue; 
     } 

     result.Rows.Add(row); 
    } 

    return result; 
} 

Bây giờ, điều cần xem xét:

  • Giải pháp này sẽ không làm việc với tính chất phức tạp
  • Tùy chỉnh bảng kết quả có thể là một chút khó khăn

Trong khi điều này có thể giải quyết vấn đề, tôi không nghĩ đây là một cách tiếp cận rất tốt, nhưng nó có thể uld là khởi đầu của một ý tưởng phong nha :)

Tôi hy vọng tôi có thể giúp lần này!

+0

Phương thức CopyToDataTable sẽ không có sẵn trong 'truy vấn' nếu tôi sử dụng nó như thế. Xin lưu ý rằng tôi đang sử dụng Entity Framework. – Zignd

+0

Tôi đã thực hiện lỗi đánh máy trên nguồn cuối cùng và khi chỉnh sửa cho biết, phương thức CopyToDataTable sẽ hoạt động ở đó. btw - Câu trả lời có giúp ích gì không? –

+0

Như bạn có thể thấy trong cùng một liên kết, để truy cập vào phương thức CopyToDataTable, kiểu T trong IEnumerable phải thuộc kiểu DataRow, nhưng thay vào đó bạn sử dụng lớp đại diện cho bảng cơ sở dữ liệu Vendedor, tôi không có quyền truy cập vào các phương thức mở rộng đó bao gồm CopyToDataTable. – Zignd

-2

bạn có thể đặt

var query = từ ....

this.dataGridViewProcura.DataSource = query.ToList()

0

Đây là một giải pháp các MSDN đề nghị: (. * Với các bổ sung nhỏ để xử lý DateTime nullable) https://msdn.microsoft.com/en-us/library/bb669096(v=vs.110).aspx

Tôi đã thực hiện nó thành công như sau:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Data; 
using System.Reflection; 


/// <summary> 
/// Converts Entity Type to DataTable 
/// </summary> 
public class ObjectShredder<T> 
{ 
    private System.Reflection.FieldInfo[] _fi; 
    private System.Reflection.PropertyInfo[] _pi; 
    private System.Collections.Generic.Dictionary<string, int> _ordinalMap; 
    private System.Type _type; 

    // ObjectShredder constructor. 
    public ObjectShredder() 
    { 
     _type = typeof(T); 
     _fi = _type.GetFields(); 
     _pi = _type.GetProperties(); 
     _ordinalMap = new Dictionary<string, int>(); 
    } 

    /// <summary> 
    /// Loads a DataTable from a sequence of objects. 
    /// </summary> 
    /// <param name="source">The sequence of objects to load into the DataTable.</param> 
    /// <param name="table">The input table. The schema of the table must match that 
    /// the type T. If the table is null, a new table is created with a schema 
    /// created from the public properties and fields of the type T.</param> 
    /// <param name="options">Specifies how values from the source sequence will be applied to 
    /// existing rows in the table.</param> 
    /// <returns>A DataTable created from the source sequence.</returns> 
    public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options) 
    { 
     // Load the table from the scalar sequence if T is a primitive type. 
     if (typeof(T).IsPrimitive) 
     { 
      return ShredPrimitive(source, table, options); 
     } 

     // Create a new table if the input table is null. 
     if (table == null) 
     { 
      table = new DataTable(typeof(T).Name); 
     } 

     // Initialize the ordinal map and extend the table schema based on type T. 
     table = ExtendTable(table, typeof(T)); 

     // Enumerate the source sequence and load the object values into rows. 
     table.BeginLoadData(); 
     using (IEnumerator<T> e = source.GetEnumerator()) 
     { 
      while (e.MoveNext()) 
      { 
       if (options != null) 
       { 
        table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options); 
       } 
       else 
       { 
        table.LoadDataRow(ShredObject(table, e.Current), true); 
       } 
      } 
     } 
     table.EndLoadData(); 

     // Return the table. 
     return table; 
    } 

    public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options) 
    { 
     // Create a new table if the input table is null. 
     if (table == null) 
     { 
      table = new DataTable(typeof(T).Name); 
     } 

     if (!table.Columns.Contains("Value")) 
     { 
      table.Columns.Add("Value", typeof(T)); 
     } 

     // Enumerate the source sequence and load the scalar values into rows. 
     table.BeginLoadData(); 
     using (IEnumerator<T> e = source.GetEnumerator()) 
     { 
      Object[] values = new object[table.Columns.Count]; 
      while (e.MoveNext()) 
      { 
       values[table.Columns["Value"].Ordinal] = e.Current; 

       if (options != null) 
       { 
        table.LoadDataRow(values, (LoadOption)options); 
       } 
       else 
       { 
        table.LoadDataRow(values, true); 
       } 
      } 
     } 
     table.EndLoadData(); 

     // Return the table. 
     return table; 
    } 

    public object[] ShredObject(DataTable table, T instance) 
    { 

     FieldInfo[] fi = _fi; 
     PropertyInfo[] pi = _pi; 

     if (instance.GetType() != typeof(T)) 
     { 
      // If the instance is derived from T, extend the table schema 
      // and get the properties and fields. 
      ExtendTable(table, instance.GetType()); 
      fi = instance.GetType().GetFields(); 
      pi = instance.GetType().GetProperties(); 
     } 

     // Add the property and field values of the instance to an array. 
     Object[] values = new object[table.Columns.Count]; 
     foreach (FieldInfo f in fi) 
     { 
      values[_ordinalMap[f.Name]] = f.GetValue(instance); 
     } 

     foreach (PropertyInfo p in pi) 
     { 
      values[_ordinalMap[p.Name]] = p.GetValue(instance, null); 
     } 

     // Return the property and field values of the instance. 
     return values; 
    } 

    public DataTable ExtendTable(DataTable table, Type type) 
    { 
     // Extend the table schema if the input table was null or if the value 
     // in the sequence is derived from type T.    
     foreach (FieldInfo f in type.GetFields()) 
     { 
      if (!_ordinalMap.ContainsKey(f.Name)) 
      { 
       // Add the field as a column in the table if it doesn't exist 
       // already. 
       DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name] 
        : table.Columns.Add(f.Name, f.FieldType); 

       // Add the field to the ordinal map. 
       _ordinalMap.Add(f.Name, dc.Ordinal); 
      } 
     } 
     foreach (PropertyInfo p in type.GetProperties()) 
     { 
      if (!_ordinalMap.ContainsKey(p.Name)) 
      { 
       // Add the property as a column in the table if it doesn't exist already. 
       DataColumn dc = table.Columns[p.Name]; 
       //Added Try Catch to account for Nullable Types 
       try 
       { 
        dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name] 
        : table.Columns.Add(p.Name, p.PropertyType); 
       } 
       catch (NotSupportedException nsEx) 
       { 
        string pType = p.PropertyType.ToString(); 
        dc = pType.Contains("System.DateTime") ? table.Columns.Add(p.Name, typeof(System.DateTime)) : table.Columns.Add(p.Name); 
        //dc = table.Columns.Add(p.Name); //Modified to above statment in order to accomodate Nullable date Time 
       } 




       // Add the property to the ordinal map. 
       _ordinalMap.Add(p.Name, dc.Ordinal); 
      } 
     } 

     // Return the table. 
     return table; 
    } 
} 

}

Thông báo trước (lớn) cho giải pháp này là ** co stly ** và bạn phải tùy chỉnh nó trong quá trình xử lý lỗi.