3

join を使用する場合、Linq の select 句で使用される匿名型を通過できないようです。クエリ結果をデータテーブルに入れたい。実行時にメモリにあるものは次のとおりです...

DataTable1 (source)
----------
col1A <int> (acting PK, not explicitly defined as such)
col1B <string>
col1C <string>
col1D <string> (FK -> dt2.col2A, also not explicitly defined)
col1E <string>

DataTable2 (source)
----------
col2A <string> (acting PK, also not explicitly defined)
col2B <string>

DataTable3 (destination)
----------
colA <int>
colB <string>
colC <string>
colD <string>

これが私が欲しいものです(私が探しているものと同等のSQL)...

INSERT INTO DataTable3 (colA, colB, colC, colD)
SELECT  dt1.col1A, dt1.col1B, dt1.col1C, dt2.col2B
FROM DataTable1 dt1
LEFT JOIN DataTable2 dt2 ON (dt1.col1D = dt2.col2A)

逆に作業すると、列挙されたクエリ結果セットをデータテーブルに配置する次の単純な行が表示されます。

DataTable DataTable3 = query.CopyToDataTable();

これが私が試したことです...これを使用できるようにする方法で「クエリ」を作成する方法がわかりません。試行 1 (var クエリを使用。これはうまくいきました。詳細をお読みください):

var query =
    from dt1 in DataTable1.AsEnumerable()
    join dt2 in DataTable2.AsEnumerable()
        on dt1.Field<string>("col1D") equals dt2.Field<string>("col2A")
    select new { col1A = dt1.Field<int>("col1A"),
        col1B = dt1.Field<string>("col1B"),
        col1C = dt1.Field<string>("col1C"),
        col2B = dt2.Field<string>("col2B") };

しかし、「query.CopyToDataTable()」で次のエラーが表示されます。

「エラー 1 型 'AnonymousType#1' は、ジェネリック型またはメソッド 'System.Data.DataTableExtensions.CopyToDataTable(System.Collections.Generic.IEnumerable)' で型パラメーター 'T' として使用できません。暗黙的な参照変換はありません。 'AnonymousType#1' から 'System.Data.DataRow' へ。"

私が推測できることから、このエラーは、「select new」が DataRows を「query」に構築しないためです。これは .CopyToDataTable() が要求します。匿名のレコードを作成するだけです。さらに、「保護レベルのためにアクセスできない」ため、クエリ要素を DataRow にキャストする方法がわかりません。

試行 2 (IEnumerable クエリを使用します。気にしないでください):

IEnumerable<DataRow> query =
    from dt1 in DataTable1.AsEnumerable()
    join dt2 in DataTable2.AsEnumerable()
        on dt1.Field<string>("col1D") equals dt2.Field<string>("col2A")
    select new { col1A = dt1.Field<int>("col1A"),
        col1B = dt1.Field<string>("col1B"),
        col1C = dt1.Field<string>("col1C"),
        col2B = dt2.Field<string>("col2B") };

これにより、「結合」でエラーが発生します。

「エラー 5 型 'System.Collections.Generic.IEnumerable' を 'System.Collections.Generic.IEnumerable' に暗黙的に変換できません。明示的な変換が存在します (キャストがありませんか?)」

ちなみに、「join」句 (および「select」内の対応する dt2 列) をコメントアウトすると、「select」で次のエラーが発生します。

「エラー 2 型 'System.Data.EnumerableRowCollection' を 'System.Collections.Generic.IEnumerable' に暗黙的に変換できません。明示的な変換が存在します (キャストがありませんか?)」

また、列を使用して DataTable3 を事前定義して、「select」句に実際の DataRow を適用しようとしましたが、「select」を利用してそれを利用することはできませんでした。


編集、詳細、解決策: 助けてくれたティムに感謝します。試行 1 (var クエリ) を使用しました。また、DataTable3 を次のように事前定義しました。

DataTable DataTable3 = new DataTable();
DataTable3.Columns.Add("colA", System.Type.GetType("System.Int32"));
DataTable3.Columns.Add("colB", System.Type.GetType("System.String"));
DataTable3.Columns.Add("colC", System.Type.GetType("System.String"));
DataTable3.Columns.Add("colD", System.Type.GetType("System.String"));

ティムが提案したように、foreach ループを使用して「クエリ」の結果を保存しました。

foreach (var x in query)
{
    DataRow newRow = DataTable3.NewRow();
    newRow.SetField("colA", x.col1A);
    newRow.SetField("colB", x.col1B);
    newRow.SetField("colC", x.col1C);
    newRow.SetField("colD", x.col2B);
    DataTable3.Rows.Add(newRow);
}

これは、いくつかの追加の努力によっていくつかの方法で一般化できますが、私の目的にはこれで十分でした。

4

2 に答える 2

6

Linq はクエリにのみ使用する必要があります。これを使用してソースをクエリし、匿名型を構築します。次に、a を使用してforeachを追加しDataRowsます。CopyToDataTable一般に、 以外には使用できませんIEnumerable<DataRow>。これが匿名型のエラーの理由です。

(私が一般的に提案しないリフレクションを使用した回避策があります:

CopyToDataTable<T>ジェネリック型TDataRowが)でない場合に実装する

私見 aforeachは非常に読みやすいので、あなたができる最善のことです:

var query =
    from dt1 in DataTable1.AsEnumerable()
    join dt2 in DataTable2.AsEnumerable()
        on dt1.Field<string>("col1D") equals dt2.Field<string>("col2A")
    select new
    {
        col1A = dt1.Field<int>("col1A"),
        col1B = dt1.Field<string>("col1B"),
        col1C = dt1.Field<string>("col1C"),
        col2B = dt2.Field<string>("col2B")
    };

foreach (var x in query)
{
    DataRow newRow = DataTable3.Rows.Add();
    newRow.SetField("col1A", x.col1A);
    newRow.SetField("col1B", x.col1B);
    newRow.SetField("col1C", x.col1C);
    newRow.SetField("col2B", x.col2B);
}
于 2013-05-15T20:28:11.043 に答える
0

次のように CopyToDataTable を利用できると思います。

dt1.AsEnumerable()
    .Join(dt2.AsEnumerable(),
        d => d.Field<string>("col1D"),
        d => d.Field<string>("col2A"),
        (d1, d2) => new { Dt1 = d1, Dt2 = d2 })
    .Select(a => {
            DataRow newRow = dt3.NewRow();
            newRow.SetField("colA", a.Dt1.Field<int>("col1A"));
            newRow.SetField("colB", a.Dt1.Field<string>("col1B"));
            newRow.SetField("colC", a.Dt1.Field<string>("col1C"));
            newRow.SetField("colD", a.Dt2.Field<string>("col2B"));
            return newRow;
        })
    .CopyToDataTable(dt3, LoadOption.OverwriteChanges);

あなたが要求したように、これは左結合ではなく内部結合を実行していることに注意してください。

本当に左結合が必要な場合は、次のものが要件を満たしていると思います。

dt1.AsEnumerable()
    .GroupJoin(dt2.AsEnumerable(),
        d1 => d1.Field<int>("col1D"),
        d2 => d2.Field<int>("col2A"),
        (l, r) => new { Left = l, Right = r })
    .Select(anon => {
            if(anon.Right.Any())
            {
                return anon.Right.Select(r =>
                {
                    var newRow = dt3.NewRow();
                    newRow.SetField("colA", anon.Left.Field<int>("col1A"));
                    newRow.SetField("colB", anon.Left.Field<string>("col1B"));
                    newRow.SetField("colC", anon.Left.Field<string>("col1C"));
                    newRow.SetField("colD", r.Field<string>("col2B"));
                    return newRow;
                });
            }
            else
            {
                var newRow = dt3.NewRow();
                newRow.SetField("colA", anon.Left.Field<int>("col1A"));
                newRow.SetField("colB", anon.Left.Field<string>("col1B"));
                newRow.SetField("colC", anon.Left.Field<string>("col1C"));
                return new DataRow[] { newRow };
            }
        })
    .Aggregate((accum, next) => accum.Union(next))
    .CopyToDataTable(dt3, LoadOption.OverwriteChanges);
于 2013-05-15T21:23:56.307 に答える