2013-08-25 183 views
5

我需要將從此LINQ返回的數據存儲到實體查詢(下面)到DataTable中,以便我可以將它用作DataGridView的數據源,我該怎麼做?LINQ to Entities查詢到DataTable

在這種情況下,我使用LINQ to Entities來針對實體框架概念模型進行查詢,因此db是一個繼承自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; 
} 

我試過這樣做(下面),但它在執行過程中會引發異常[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]:異常:InvalidCastException

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

在此先感謝

回答

2

這裏有一個重要的事情,你是鑄造你的LINQ查詢(IEnumerable<DataRow>)當你選擇vendedor,所以我認爲vendedor是Vendedor的一個實例,所以你的查詢將返回一個IEnumerable<Vendedor>

這應該解決您的問題,而且,您是否可以嘗試將生成的DataTable用作DataGridView的DataSource?這將是這樣的:

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; 

希望我能幫助!

編輯

作爲一個方面(和非常個人化)注意,你可以嘗試使用您選擇的lambda表達式,它們看起來更漂亮:)

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

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

會更加清晰,你不認爲?

EDIT 2 我剛剛意識到你說的對CopyToDataTable是對的DataRow而已,所以最後的(當然不那麼幹淨)解決方案是模仿助手中的邏輯是什麼?現在

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

事情要考慮

  • 該解決方案不會複雜性
  • 自定義生成的表的工作可能是一個有點棘手

雖然這可能會解決這個問題,我不認爲這是一個很好的方法,但它合作這是一個不錯的想法:)

我希望我能幫助這次!

+0

如果我像這樣使用方法CopyToDataTable在'query'中將不可用。請注意,我正在使用實體框架。 – Zignd

+0

我在最後一個源文件上輸入了錯字,並且正如編輯所說,CopyToDataTable方法應該在那裏工作。順便說一句 - 答案有幫助嗎? –

+0

正如你可以在同一個鏈接中看到的,爲了獲得對CopyToDataTable方法的訪問,IEnumerable 中的T類型必須是DataRow類型,但是相反,您使用了表示數據庫表Vendedor的類,最終我無法訪問那些包含CopyToDataTable的擴展方法。 – Zignd

-2

你可以把

VAR的查詢=從....

this.dataGridViewProcura.DataSource =查詢。tolist()

0

這是一個在MSDN推薦的解決方案:(。*輕微增加處理可空的DateTime)https://msdn.microsoft.com/en-us/library/bb669096(v=vs.110).aspx

我已經實現了它成功 如下:

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

}

這個解決方案的(大)警告是它是** co狡猾的**,你必須在錯誤處理中定製它。