2016-03-28 6 views
0

SQLサーバーからフラット形式の階層データを取得しています。これがデータの見た目です。C#でグルーピング、動的キーの作成、情報の取得、およびjson出力の生成

Group  Name  Level Parent  Value1  Value2 RowID 
Global  Product1  1      10   20  1 
APAC  Product1  1      80   90  2 
EMEA  Product1  1      50   70  3 
Global  Product2  2  Product1  100   200  4 
APAC  Product2  2  Product1  800   900  5 
EMEA  Product2  2  Product1  500   700  6 
Global  Product3  3  Product2  10   20  7 
APAC  Product3  3  Product2  80   90  8 
Global  Product4  4  Product3  110   120  9 
APAC  Product4  4  Product3  810   190  10 
EMEA  Product4  4  Product3  510   170  11 
..... 
..... 
Global  Product12  1      10   20  100 

私はグループにName and Level列に基づいてデータを必要とします。次に、Group Column & Value1 & Value2 columnsの組み合わせに基づいて複数のキーを作成する必要があります。出力の詳細については、JSON出力を参照してください。グループの番号は変更可能ですのでご注意ください。

[ 
    { 
    Id: 1, 
    Name: Product1, 
    parentId: null, 
    GlobalValue1: 10, 
    GlobalValue2: 20, 
    APACValue1: 80, 
    APACValue2: 90, 
    EMEAValue1: 50, 
    EMEAValue2: 70 
    }, 
    { 
    Id: 2, 
    Name: Product2, 
    parentId: 1, 
    GlobalValue1: 100, 
    GlobalValue2: 200, 
    APACValue1: 800, 
    APACValue2: 900, 
    EMEAValue1: 500, 
    EMEAValue2: 700 
    }, 
    { 
    Id: 3, 
    Name: Product3, 
    parentId: 2, 
    GlobalValue1: 10, 
    GlobalValue2: 20, 
    APACValue1: 80, 
    APACValue2: 90, 
    EMEAValue1: null, 
    EMEAValue2: null 
    }, 
    { 
    Id: 4, 
    Name: Product4, 
    parentId: 3, 
    GlobalValue1: 110, 
    GlobalValue2: 120, 
    APACValue1: 810, 
    APACValue2: 190, 
    EMEAValue1: 510, 
    EMEAValue2: 170 
    }{ 
    Id: 122, 
    Name: Product12, 
    parentId: null3, 
    GlobalValue1: 10, 
    GlobalValue2: 20, 
    APACValue1: null, 
    APACValue2: null, 
    EMEAValue1: null, 
    EMEAValue2: null 
    } 



] 

IDフィールドを自動生成する必要があります。このフィールドは、親子関係を確立するために使用されます。 I cannot rely on名前column as it can repeat (can have same value) across different levels.。 1つ以上の製品と各レベルがあります。私の例では、単純な例を保つために、レベルごとに1つの製品を表示しています。

+0

あなたがあなたのテーブルから辞書を作成し、そのをシリアル化したいような音。たとえば、[this](http://www.newtonsoft.com/json/help/html/serializedictionary.htm)を参照してください。 –

+0

@MattBurland:迅速な返信をありがとう。私が間違っていれば私を修正してください。しかし、これは車輪にあるちょうどコグです。データをシリアル化する方法を教えてくれます。しかし、私がそれをする前に、私はキーを生成し、親子関係を管理する方法を理解する必要があります。データをどのようにグループ化するのですか? null値はどのように管理しますか。私は特定のアイデアを持っていますが、動いている部分が多すぎます。私は少し混乱しています。 – OpenStack

+0

あなたの質問は、関係がどのように働くべきかについては完全にはっきりしていませんが、*私はあなたが 'Level'でグループ化しようとしていると思います(' Level'と 'Name'は基本的に1対1です)各グループの各項目について、辞書を作成し、 'Group'と列名(' Value1'、 'Value2')を連結して辞書キーを作成し、関連する値を入力します。全部。出力の中のあなたの「Id」がどこから来るのかは明らかではありません。それはちょうどレベルですか? –

答えて

1

ここに、私が望むと思うことをするコードがあります。それはコンソールアプリケーションで、私はJSONを作成するためにNewtonsoft.Jsonを使用しました(NuGetを参考にしてください)。 POCOオブジェクトに

class Program 
{ 
    static void Main(string[] args) 
    { 
     var data = initData(); 
     var result = getGroupedData(data); 
     var json = new Newtonsoft.Json.JsonSerializer 
     { 
      Formatting=Formatting.Indented 
     }; 
     json.Serialize(Console.Out,result); 
     Console.ReadKey(); 
    } 

    private static object getGroupedData(DataTable dt) 
    { 
     var id = 1; 
     var rows = dt.Rows.OfType<DataRow>(); //because for some reason DataRowCollection is not an IEnumerable<DataRow> 
     var products = rows //the products, each defined by Name and Level 
      .GroupBy(r => new { Name = r.Field<string>("Name"), Level = r.Field<int>("Level") }) 
      .Select(g => new 
      { 
       Id = id++, //create the id 
       Name = g.Key.Name, 
       Level = g.Key.Level, 
       // select the parent and throw exception if there are more or less than one 
       Parent = g.Select(r => r.Field<string>("Parent")).Distinct().Single() 
      }).ToList(); 
     var results = products 
      .Select(p => new //need a partial result first, containing the Global, Apac and Emea rows, if they exist 
      { 
       Id = p.Id, 
       Name = p.Name, 
       // Assuming the Level of a child is Level of parent+1 
       Parent = products.FirstOrDefault(par => par.Name == p.Parent && par.Level + 1 == p.Level), 
       Global = rows.FirstOrDefault(r => r.Field<string>("Name") == p.Name && r.Field<int>("Level") == p.Level && r.Field<string>("Group") == "Global"), 
       Apac = rows.FirstOrDefault(r => r.Field<string>("Name") == p.Name && r.Field<int>("Level") == p.Level && r.Field<string>("Group") == "APAC"), 
       Emea = rows.FirstOrDefault(r => r.Field<string>("Name") == p.Name && r.Field<int>("Level") == p.Level && r.Field<string>("Group") == "EMEA") 
      }) 
      .Select(x => new //create the final result 
      { 
       Id = x.Id, 
       Name = x.Name, 
       ParentId = x.Parent==null? (int?)null :x.Parent.Id, 
       GlobalValue1 = x.Global == null ? (double?)null : x.Global.Field<double?>("Value1"), 
       GlobalValue2 = x.Global == null ? (double?)null : x.Global.Field<double?>("Value2"), 
       APACValue1 = x.Apac == null ? (double?)null : x.Apac.Field<double?>("Value1"), 
       APACValue2 = x.Apac == null ? (double?)null : x.Apac.Field<double?>("Value2"), 
       EMEAValue1 = x.Emea == null ? (double?)null : x.Emea.Field<double?>("Value1"), 
       EMEAValue2 = x.Emea == null ? (double?)null : x.Emea.Field<double?>("Value2") 
      }) 
      .ToArray(); 
     return results; 
    } 

    private static DataTable initData() 
    { 
     var dt = new DataTable(); 
     dt.Columns.Add("Group", typeof(string)); 
     dt.Columns.Add("Name", typeof(string)); 
     dt.Columns.Add("Level", typeof(int)); 
     dt.Columns.Add("Parent", typeof(string)); 
     dt.Columns.Add("Value1", typeof(double)); 
     dt.Columns.Add("Value2", typeof(double)); 
     dt.Columns.Add("RowID", typeof(int)); 
     dt.Rows.Add("Global", "Product1", 1, null, 10, 20, 1); 
     dt.Rows.Add("APAC", "Product1", 1, null, 80, 90, 2); 
     dt.Rows.Add("EMEA", "Product1", 1, null, 50, 70, 3); 
     dt.Rows.Add("Global", "Product2", 2, "Product1", 100, 200, 1); 
     dt.Rows.Add("APAC", "Product2", 2, "Product1", 800, 900, 2); 
     dt.Rows.Add("EMEA", "Product2", 2, "Product1", 500, 700, 3); 
     dt.Rows.Add("Global", "Product3", 3, "Product2", 10, 20, 1); 
     dt.Rows.Add("APAC", "Product3", 3, "Product2", 80, 90, 2); 
     dt.Rows.Add("Global", "Product4", 4, "Product3", 110, 120, 1); 
     dt.Rows.Add("APAC", "Product4", 4, "Product3", 810, 190, 2); 
     dt.Rows.Add("EMEA", "Product4", 4, "Product3", 510, 170, 3); 
     return dt; 
    } 
} 

、この方法は、次のようになります。

private static object getGroupedData(IEnumerable<MyPoco> rows) 
{ 
    var id = 1; 
    var products = rows //the products, each defined by Name and Level 
     .GroupBy(r => new { Name = r.Name, Level = r.Level }) 
     .Select(g => new 
     { 
      Id = id++, //create the id 
      Name = g.Key.Name, 
      Level = g.Key.Level, 
      // select the parent and throw exception if there are more or less than one 
      Parent = g.Select(r => r.Parent).Distinct().Single() 
     }).ToList(); 
    var results = products 
     .Select(p => new //need a partial result first, containing the Global, Apac and Emea rows, if they exist 
     { 
      Id = p.Id, 
      Name = p.Name, 
      // Assuming the Level of a child is Level of parent+1 
      Parent = products.FirstOrDefault(par => par.Name == p.Parent && par.Level + 1 == p.Level), 
      Global = rows.FirstOrDefault(r => r.Name == p.Name && r.Level == p.Level && r.Group == "Global"), 
      Apac = rows.FirstOrDefault(r => r.Name == p.Name && r.Level == p.Level && r.Group == "APAC"), 
      Emea = rows.FirstOrDefault(r => r.Name == p.Name && r.Level == p.Level && r.Group == "EMEA") 
     }) 
     .Select(x => new //create the final result 
     { 
      Id = x.Id, 
      Name = x.Name, 
      ParentId = x.Parent==null? (int?)null :x.Parent.Id, 
      GlobalValue1 = x.Global == null ? (double?)null : x.Global.Value1, 
      GlobalValue2 = x.Global == null ? (double?)null : x.Global.Value2, 
      APACValue1 = x.Apac == null ? (double?)null : x.Apac.Value1, 
      APACValue2 = x.Apac == null ? (double?)null : x.Apac.Value2, 
      EMEAValue1 = x.Emea == null ? (double?)null : x.Emea.Value1, 
      EMEAValue2 = x.Emea == null ? (double?)null : x.Emea.Value2 
     }) 
     .ToArray(); 
    return results; 
} 
+0

あなたの名前+レベルの統一性を要求されたために更新しました。名前は –

+0

です。迅速な返信と複数の編集をありがとうございます。私はこの場合、 'dt'はデータ可能であると仮定します。この行が '' ParentId = products.FirstOrDefault(par => par.Name == p.Parent && par.Level + 1 == p.Level)?Id. 'の処理をしています。私はこのコードをコンパイルできません。あなたは何をしているのか説明してください。私はコードを順応できるものにします。 – OpenStack

+0

開始データがDataTableでない場合はずっと簡単です。あなたが指定しなかったので、私は「フラットSQLデータ」はDataTableまたはDataReaderのいずれかを意味すると仮定しました。短いプロジェクトを作って、コンパイル可能なコメント付きの正しいコードを教えてください。 –

関連する問題