ここに、私が望むと思うことをするコードがあります。それはコンソールアプリケーションで、私は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;
}
あなたがあなたのテーブルから辞書を作成し、そのをシリアル化したいような音。たとえば、[this](http://www.newtonsoft.com/json/help/html/serializedictionary.htm)を参照してください。 –
@MattBurland:迅速な返信をありがとう。私が間違っていれば私を修正してください。しかし、これは車輪にあるちょうどコグです。データをシリアル化する方法を教えてくれます。しかし、私がそれをする前に、私はキーを生成し、親子関係を管理する方法を理解する必要があります。データをどのようにグループ化するのですか? null値はどのように管理しますか。私は特定のアイデアを持っていますが、動いている部分が多すぎます。私は少し混乱しています。 – OpenStack
あなたの質問は、関係がどのように働くべきかについては完全にはっきりしていませんが、*私はあなたが 'Level'でグループ化しようとしていると思います(' Level'と 'Name'は基本的に1対1です)各グループの各項目について、辞書を作成し、 'Group'と列名(' Value1'、 'Value2')を連結して辞書キーを作成し、関連する値を入力します。全部。出力の中のあなたの「Id」がどこから来るのかは明らかではありません。それはちょうどレベルですか? –