2013-08-25 15 views
5

Ho bisogno di memorizzare i dati restituiti da questo LINQ alla query Entities (sotto) in un DataTable in modo che possa utilizzarlo come origine dati per un DataGridView, come posso farlo?LINQ alle entità query a DataTable

In questo caso sto utilizzando LINQ alle entità per eseguire una query su un modello concettuale Entity Framework, quindi db è una classe che eredita da 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; 
} 

Ho provato a farlo (sotto), ma genera un'eccezione durante l'esecuzione [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]: Eccezione: InvalidCastException

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

Grazie in anticipo

risposta

2

C'è una cosa importante qui, si sta casting la query LINQ to (IEnumerable<DataRow>) quando si seleziona il vendedor, quindi presumo che il vendedor sia un'istanza di Vendedor, quindi la tua query restituirà un IEnumerable<Vendedor>

Questo dovrebbe risolvere il tuo problema, ma puoi provare a utilizzare il DataTable generato come DataSource per il tuo DataGridView? Sarebbe qualcosa del genere:

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; 

Spero di poterti aiutare!

EDIT

Come un lato (e molto personale) nota, si potrebbe provare a utilizzare lambda sul vostro prescelto, hanno un aspetto più bello :)

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

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

molto più pulito, non è vero pensare?

EDIT 2 ho appena capito quello che hai detto sul CopyToDataTable essere per DataRow solo, così lo scorso (certamente non così pulito) soluzione sarebbe quella di imitare la logica sulla aiutante?

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

Ora, cose da considerare:

  • Questa soluzione volontà non lavoro con proprietà complesse
  • Personalizzazione della tabella risultante potrebbe essere un po 'complicato

Mentre questo potrebbe risolvere il problema, non penso che questo sia un approccio molto buono, ma è co uld essere l'inizio di una buona idea :)

Spero di poter aiutare questa volta!

+0

Il metodo CopyToDataTable non sarà disponibile in 'query' se lo utilizzo in questo modo. Si noti che sto utilizzando Entity Framework. – Zignd

+0

Ho fatto un refuso sull'ultima fonte e, come dice la modifica, il metodo CopyToDataTable dovrebbe funzionare lì. btw - La risposta è stata di aiuto? –

+0

Come puoi vedere nello stesso link, per accedere al metodo CopyToDataTable il tipo T nell'Enumerable deve essere di tipo DataRow, ma come invece hai usato la classe che rappresenta la tabella del database Vendedor I non ha accesso a quei metodi di estensione che include CopyToDataTable. – Zignd

-2

si può mettere

var query = da ....

this.dataGridViewProcura.DataSource = query.ToList()

0

Questa è una soluzione del MSDN consigliata: (. * Con aggiunte minori per gestire DateTime nullable) https://msdn.microsoft.com/en-us/library/bb669096(v=vs.110).aspx

ho implementato con successo come segue:

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

}

Il (grande) avvertimento a questa soluzione è che è ** co stly ** e devi personalizzarlo nella gestione degli errori.