2012-06-26 13 views
5

これを説明するいくつかの記事を見てきましたが、私の場合はそれを理解できません。私はテーブルを注文するPIVOTコマンドを使用してSQLクエリを持っていた、私はLINQを介して私たちのアプリにこのロジックを移動しようとしています。テーブルはDataTableに格納され、次のようになります。DataTableのピボットロジックLINQ

ObjectName | ColumnName | Property | Value 
---------------------------------------------- 
foo  | bar   | a   | w 
foo  | bar   | b   | x 
foo  | bar   | c   | y 
foo  | bar   | d   | z 
foo  | test  | a   | i 
foo  | test  | b   | j 
foo  | test  | c   | k 
foo  | test  | d   | l 

このように見えるDataTableに変換します。

ObjectName | ColumnName | a | b | c | d 
--------------------------------------------------- 
foo   | bar   | w | x | y | z 
foo   | test  | i | j | k | l 

だから私は... ObjectNameのを(何らかの理由でそれを追加するために私にコンパイルエラーを与えていた?)が含まれていません

var query = dt.AsEnumerable() 
    .GroupBy(row => row.Field<string>("ColumnName")) 
    .Select(g => new { 
     ColumnName = g.Key, 
     a = g.Where(row => row.Field<string>("Property") == "a").Select(c => c.Field<string>("Value")), 
     b = g.Where(row => row.Field<string>("Property") == "b").Select(c => c.Field<string>("Value")), 
     c = g.Where(row => row.Field<string>("Property") == "c").Select(c => c.Field<string>("Value")), 
     d = g.Where(row => row.Field<string>("Property") == "d").Select(c => c.Field<string>("Value")) 
    }); 

をこのような何かを試してみました。デバッガを見ると、ColumnNameは右に表示されていますが、残りはほとんど不器用です。申し訳ありませんが、私のLINQのスキルはかなり劣っています。私は勉強しようとしていますが、簡単に混乱します。

私のデータ型は、その拡張メソッドを使用できるように正しく出力されていないと推測していますが、私は頭の中に少しあります。助言がありますか?

編集それでも、私はこの行

DataTable newDT = query.CopyToDataTable(); 

と戦っていますいくつかのエラーを取得しますが、私は

型「AnonymousTypeの#1」は型パラメータ「Tとして使用することはできませんエラーメッセージを取得します' ジェネリック型またはメソッド ' System.Data.DataTableExtensions.CopyToDataTable (System.Collections.Generic.IEnumerable) ''。 'AnonymousType#1'から 'System.Data.DataRow'への参照変換は暗黙のうちに にはありません。

+0

することができますあなたが得ている出力を投稿しますか? –

答えて

4

このお試しください:ここで

class Program 
{ 
//Helper method to make the Select cleaner: 
private static string GetProperty(IEnumerable<DataRow> rows, string propertyName) 
{ 
    return rows 
     .Where(row => row.Field<string>("Property") == propertyName) 
     .Select(c => c.Field<string>("Value")) 
     .FirstOrDefault(); 
} 

//helper method for populating the datatable 
private static void addRow(DataTable dt, string objectName, string columnName 
    , string property, string value) 
{ 
    var row = dt.NewRow(); 
    row["ObjectName"] = objectName; 
    row["ColumnName"] = columnName; 
    row["Property"] = property; 
    row["Value"] = value; 
    dt.Rows.Add(row); 
} 

public static void Main(string[] args) 
{ 

    DataTable dt = new DataTable(); 
    dt.Columns.Add("ObjectName"); 
    dt.Columns.Add("ColumnName"); 
    dt.Columns.Add("Property"); 
    dt.Columns.Add("Value"); 

    addRow(dt, "foo", "bar", "a", "w"); 
    addRow(dt, "foo", "bar", "b", "x"); 
    addRow(dt, "foo", "bar", "c", "y"); 
    addRow(dt, "foo", "bar", "d", "z"); 
    addRow(dt, "foo", "test", "a", "i"); 
    addRow(dt, "foo", "test", "b", "j"); 
    addRow(dt, "foo", "test", "c", "k"); 
    addRow(dt, "foo", "test", "d", "l"); 

    var query = dt.AsEnumerable() 
     .GroupBy(row => new 
     { 
      ObjectName = row.Field<string>("ObjectName"), 
      ColumnName = row.Field<string>("ColumnName") 
     }) 
     .Select(g => new 
     { 
      ObjectName = g.Key.ObjectName, 
      ColumnName = g.Key.ColumnName, 
      a = GetProperty(g, "a"), 
      b = GetProperty(g, "b"), 
      c = GetProperty(g, "c"), 
      d = GetProperty(g, "d"), 
     }) 
     .CopyToDataTable(); 

    foreach (DataRow row in query.Rows) 
    { 
     foreach (DataColumn column in query.Columns) 
     { 
      System.Console.Write(row[column] + "\t"); 
     } 
     System.Console.WriteLine(); 
    } 


    Console.WriteLine("Press any key to exit. . ."); 
    Console.ReadKey(true); 
} 
} 

は、私はあなたが使用していたものを述べるなかったので、datattableにコピーするために使用しているコードです:

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


/// <summary> 
/// Code copied directly from http://msdn.microsoft.com/en-us/library/bb669096.aspx 
/// </summary> 
/// <typeparam name="T"></typeparam> 
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.Contains(p.Name) ? table.Columns[p.Name] 
        : table.Columns.Add(p.Name, p.PropertyType); 

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

     // Return the table. 
     return table; 
    } 
} 

/// <summary> 
/// Code copied directly from http://msdn.microsoft.com/en-us/library/bb669096.aspx 
/// </summary> 
public static class CustomLINQtoDataSetMethods 
{ 
    public static DataTable CopyToDataTable<T>(this IEnumerable<T> source) 
    { 
     return new ObjectShredder<T>().Shred(source, null, null); 
    } 

    public static DataTable CopyToDataTable<T>(this IEnumerable<T> source, 
               DataTable table, LoadOption? options) 
    { 
     return new ObjectShredder<T>().Shred(source, table, options); 
    } 

} 
+0

私はこのコードを実行し、それが実行され、予想される結果が表示されます。私は答えを完全にコンパイル可能な実行可能プログラムに変更しました。 – Servy

+0

うわー、ありがとう、私はそれを全く理解していないので、そのモンスターメソッドでMSDNの記事を避けることができると期待していましたが、これは私が想定しているより良い方法を見つけるまでは今のところ機能します。 –

+0

これはすばらしい解決策です。私が扱いたい1つのテストは、1つの列がない場合です。例えば、以下のデータ: 'addRow(dt、" foo "、" bar "、" a "、" w "); addRow(dt、 "foo"、 "bar"、 "c"、 "y");addRow(dt、 "foo"、 "bar"、 "d"、 "z"); addRow(dt、 "foo"、 "test"、 "a"、 "i");addRow(dt、 "foo"、 "test"、 "c"、 "k"); addRow(dt、 "foo"、 "test"、 "d"、 "l"); ' – mpora