uso

雑記いろいろ
★書いてある内容に保証は一切ありません。
 ご自身で判断をしてください。

[C# .NET] 小ネタ2

2014-07-21 03:31:53 | work
■DataTableで親子孫関係のデータを取得する方法

参考:
http://msdn.microsoft.com/ja-jp/library/bb386943(v=vs.110).aspx
http://teruc.dnsalias.net/blog/2009/11/02/22
http://www.atmarkit.co.jp/fdotnet/extremecs/extremecs_15/extremecs_15_01.html


★問題点
 親子までしか左外部結合の場合、2テーブルまでしかできない。
 親子孫の3テーブルができない。

 親ー子1
 親ー子2

 ならいくつかサンプルがあるが、親子孫は無理なのか?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create DataSet
            DataSet ds = CreateDataSet();

            // Create Data
            SetData(ref ds);

            // Out Put Console
            //OutPutData(ds);

            // query
            DataTable ptbl = ds.Tables["parent"];
            DataTable ctbl = ds.Tables["child"];
            DataTable gctbl = ds.Tables["grandchild"];

            byte[] p1 = System.Text.Encoding.Unicode.GetBytes("1");

            // join

            // 3テーブルの内部結合
            var q1 = from p in ptbl.AsEnumerable()
                     where p.Field<byte[]>("id").SequenceEqual(p1)
                     join c in ctbl.AsEnumerable()
                     on p.Field<byte[]>("id") equals c.Field<byte[]>("pid")
                     join gc in gctbl.AsEnumerable()
                     on c.Field<byte[]>("id") equals gc.Field<byte[]>("pid")
                     select new
                     {
                         pid = p["id"],
                         pvalue = p["value1"],
                         cid = c["id"],
                         cvalue1 = c["value3"],
                         gcid = gc["id"],
                         gcvalue1 = gc["value5"]

                     };

            foreach (var test in (from q in q1 where q.gcvalue1.ToString() == "子20孫21" select q))
            {
                Console.WriteLine(test.pvalue);
                Console.WriteLine(test.cvalue1);
                Console.WriteLine(test.gcvalue1);
            }

            // 外部結合(子孫(子のデータが孫にない場合あり)2テーブルまでしかできない?)
            Console.WriteLine();

            var q2 = from c in ctbl.AsEnumerable()
                     join gc in gctbl.AsEnumerable()
                     on c.Field<byte[]>("id") equals gc.Field<byte[]>("pid")
                     into groupData
                     from data in groupData.DefaultIfEmpty()
                     select new
                     {
                         cid = c["id"],
                         cvalue = c["value3"],
                         // 孫がない場合、初期値を設定する
                         gcid = (data == null ? new byte[] { 0 } : data["id"]),
                         gcvalue1 = (data == null ? "no grand child" : data["value5"]),
                     };

            foreach (var test in q2)
            {
                Console.WriteLine(test.cvalue);
                Console.WriteLine(test.gcvalue1);
            }


            // グループ結合(2テーブルまでしかできない?)
            // 親1
            // 子1_1
            // 子1_2
            // 親2・・・
            Console.WriteLine();

            var q3 = from p in ptbl.AsEnumerable()
                     join c in ctbl.AsEnumerable()
                     on p.Field<byte[]>("id") equals c.Field<byte[]>("pid")
                         /*join gc in gctbl.AsEnumerable()
                         on c.Field<byte[]>("id") equals gc.Field<byte[]>("pid")*/
                     into g
                     select new
                     {
                         pid = p["id"],
                         pvalue = p["value1"],
                         cinfo = g,
                     };

            foreach (var test in q3)
            {
                Console.WriteLine(test.pvalue);
                foreach (var test2 in test.cinfo)
                {
                    Console.WriteLine(test2.Field<string>("value3"));
                }
            }


            Console.Read();

        }

        // DataSet Create
        static DataSet CreateDataSet()
        {
            var ds = new DataSet();

            // parent table
            var ptbl = new DataTable();
            {
                var pcolumn = new DataColumn[]{
                              new DataColumn("id", typeof(byte[]))
                             ,new DataColumn("pid", typeof(byte[]))
                             ,new DataColumn("value1", typeof(string))
                             ,new DataColumn("value2", typeof(int))
                             };

                ptbl.Columns.AddRange(pcolumn);
                ptbl.TableName = "parent";
            }

            // child table
            var ctbl = new DataTable();
            {
                var ccolumn = new DataColumn[]{
                              new DataColumn("id", typeof(byte[]))
                             ,new DataColumn("pid", typeof(byte[]))
                             ,new DataColumn("value3", typeof(string))
                             ,new DataColumn("value4", typeof(int))
                             };

                ctbl.Columns.AddRange(ccolumn);
                ctbl.TableName = "child";
            }

            // grandchild table
            var gctbl = new DataTable();
            {
                var gccolumn = new DataColumn[]{
                              new DataColumn("id", typeof(byte[]))
                             ,new DataColumn("pid", typeof(byte[]))
                             ,new DataColumn("value5", typeof(string))
                             ,new DataColumn("value6", typeof(int))
                             };

                gctbl.Columns.AddRange(gccolumn);
                gctbl.TableName = "grandchild";
            }

            // Create DataSet parent child grandchild
            ds.Tables.Add(ptbl);
            ds.Tables.Add(ctbl);
            ds.Tables.Add(gctbl);

            return ds;
        }

        // Data Create
        static void SetData(ref DataSet ds)
        {
            // parent id have two child
            byte[] p1 = System.Text.Encoding.Unicode.GetBytes("1");
            byte[] p2 = System.Text.Encoding.Unicode.GetBytes("2");
            byte[] p3 = System.Text.Encoding.Unicode.GetBytes("3");
            // have only child
            byte[] p4 = System.Text.Encoding.Unicode.GetBytes("4");

            // child id have one child
            byte[] c1 = System.Text.Encoding.Unicode.GetBytes("10");
            byte[] c2 = System.Text.Encoding.Unicode.GetBytes("20");
            byte[] c3 = System.Text.Encoding.Unicode.GetBytes("30");
            byte[] c4 = System.Text.Encoding.Unicode.GetBytes("40");
            byte[] c5 = System.Text.Encoding.Unicode.GetBytes("50");
            byte[] c6 = System.Text.Encoding.Unicode.GetBytes("60");
            byte[] c7 = System.Text.Encoding.Unicode.GetBytes("70");

            // grand child id
            byte[] gc1 = System.Text.Encoding.Unicode.GetBytes("11");
            byte[] gc2 = System.Text.Encoding.Unicode.GetBytes("21");
            byte[] gc3 = System.Text.Encoding.Unicode.GetBytes("31");
            byte[] gc4 = System.Text.Encoding.Unicode.GetBytes("41");
            byte[] gc5 = System.Text.Encoding.Unicode.GetBytes("51");
            byte[] gc6 = System.Text.Encoding.Unicode.GetBytes("61");

            DataTable ptbl = ds.Tables["parent"];
            DataTable ctbl = ds.Tables["child"];
            DataTable gctbl = ds.Tables["grandchild"];

            ptbl.LoadDataRow(new object[] { p1, DBNull.Value, "親1", 1 }, true);
            ptbl.LoadDataRow(new object[] { p2, DBNull.Value, "親2", 2 }, true);
            ptbl.LoadDataRow(new object[] { p3, DBNull.Value, "親3", 3 }, true);
            ptbl.LoadDataRow(new object[] { p4, DBNull.Value, "親4", 4 }, true);

            ctbl.LoadDataRow(new object[] { c1, p1, "親1子10", 10 }, true);
            ctbl.LoadDataRow(new object[] { c2, p1, "親1子20", 20 }, true);
            ctbl.LoadDataRow(new object[] { c3, p2, "親2子30", 30 }, true);
            ctbl.LoadDataRow(new object[] { c4, p2, "親2子40", 40 }, true);
            ctbl.LoadDataRow(new object[] { c5, p3, "親3子50", 50 }, true);
            ctbl.LoadDataRow(new object[] { c6, p3, "親3子60", 60 }, true);
            ctbl.LoadDataRow(new object[] { c7, p4, "親4子70", 70 }, true);

            gctbl.LoadDataRow(new object[] { gc1, c1, "子10孫11", 11 }, true);
            gctbl.LoadDataRow(new object[] { gc2, c2, "子20孫21", 21 }, true);
            gctbl.LoadDataRow(new object[] { gc3, c3, "子30孫31", 31 }, true);
            gctbl.LoadDataRow(new object[] { gc4, c4, "子40孫41", 41 }, true);
            gctbl.LoadDataRow(new object[] { gc5, c5, "子50孫51", 51 }, true);
            gctbl.LoadDataRow(new object[] { gc6, c6, "子60孫61", 61 }, true);

        }

        // Out Console
        static void OutPutData(DataSet ds)
        {
            foreach (DataTable dt in ds.Tables)
            {
                Console.WriteLine("***");

                Console.WriteLine(dt.TableName);
                Console.WriteLine("");

                foreach (DataColumn col in dt.Columns)
                {
                    Console.Write(col.ColumnName + " ");
                }
                Console.WriteLine("");
                foreach (DataRow dr in dt.Rows)
                {
                    foreach (DataColumn col in dt.Columns)
                    {
                        if (dr[col.ColumnName].GetType() == typeof(byte[]))
                        {
                            // change unicode
                            byte[] data = (byte[])dr[col.ColumnName];
                            string strFromByte = Encoding.Unicode.GetString(data);
                            Console.Write(strFromByte + " ");
                        }
                        else
                        {
                            Console.Write(dr[col.ColumnName] + " ");
                        }
                    }
                    Console.WriteLine("");

                }
                Console.WriteLine("");
            }
        }
    }
}