2013-08-25 12 views
5

Ich muss die Daten von dieser Abfrage LINQ to Entities (unten) in eine DataTable speichern, so dass ich es als Datenquelle zu einem DataGridView verwenden kann, wie kann ich das tun?LINQ zu Entities Abfrage zu DataTable

In diesem Fall verwende ich LINQ zu Entities, um gegen ein konzeptionelles Modell von Entity Framework abzufragen, also db ist eine Klasse, die von System.Data.Entity.DbContext erbt.

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

Ich habe versucht, dies zu tun (unten), aber es wirft eine Ausnahme während der Ausführung [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]: Ausnahme: InvalidCastException

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

Vielen Dank im Voraus

Antwort

2

Es ist eine wichtige Sache hier, Sie werfen Ihre Linq-Abfrage (IEnumerable<DataRow>), wenn Sie das sind die Auswahl vendedor, so gehe ich davon aus, dass vendedor ist eine Instanz Vendedor, so dass Ihre Abfrage wird wieder ein IEnumerable<Vendedor>

Das sollte Ihr Problem lösen, aber können Sie auch versuchen, die generierte DataTable als DataSource für Ihr DataGridView zu verwenden? Es würde so etwas sein:

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; 

Hoffe ich kann helfen!

EDIT

Als Seite (und sehr persönlich) zur Kenntnis, könnten Sie mit Lambda-Ausdrücke auf Ihrem wählen versuchen, sie schönere aussehen :)

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

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

viel sauberer, nicht wahr denken?

EDIT 2 Ich habe erkannt, genau das, was Sie auf CopyToDataTable für DataRow zu sein, sagte nur, so zuletzt (zugegebenermaßen nicht so sauber) Lösung, die Logik auf dem Helfer zu imitieren wäre?

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

Jetzt Dinge beachten:

  • Diese Lösung nicht Arbeit mit komplexen Eigenschaften
  • die resultierende Tabelle Customizing könnte ein bisschen schwierig

Während sein Dies könnte das Problem lösen, ich denke nicht, dass dies ein sehr guter Ansatz ist, aber es co Seid der Anfang einer anständigen Idee :)

Ich hoffe, ich kann diesmal helfen!

+0

Die Methode CopyToDataTable ist in der 'query' nicht verfügbar, wenn ich sie so verwende. Bitte beachten Sie, dass ich Entity Framework verwende. – Zignd

+0

Ich habe einen Tippfehler bei der letzten Quelle gemacht, und wie die Änderung sagt, sollte die CopyToDataTable Methode dort arbeiten. BTW: Hat die Antwort überhaupt geholfen? –

+0

Wie Sie im selben Link sehen können, muss der Typ T in der IEnumerable vom Typ DataRow sein, um Zugriff auf die CopyToDataTable-Methode zu erhalten, aber stattdessen haben Sie die Klasse verwendet, die die Datenbanktabelle Vendedor darstellt diese Erweiterungsmethoden, die die CopyToDataTable enthält. – Zignd

-2

können Sie

var Abfrage setzen = von ....

this.dataGridViewProcura.DataSource = Abfrage.ToList()

0

Dies ist eine der MSDN empfohlene Lösung: (. * Mit geringfügigen Ergänzungen NULL festlegbare Datetime zu handhaben) https://msdn.microsoft.com/en-us/library/bb669096(v=vs.110).aspx

I Umgesetzt haben sie erfolgreich wie folgt:

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

}

Der (große) Vorbehalt zu dieser Lösung ist, dass es ** co ist stly ** und Sie müssen es in der Fehlerbehandlung anpassen.