如何通过自定义连接将此Linq查询转换为DataSet?

ave*_*oo7 3 c# linq join anonymous datarow

在使用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>
Run Code Online (Sandbox Code Playgroud)

这就是我想要的(SQL equivelant到我正在寻找的)......

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)
Run Code Online (Sandbox Code Playgroud)

向后工作,我看到这个简单的行将枚举查询结果集放入数据表中:

DataTable DataTable3 = query.CopyToDataTable();
Run Code Online (Sandbox Code Playgroud)

这是我尝试过的...我不知道如何以允许我使用它的方式构建'查询'.尝试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") };
Run Code Online (Sandbox Code Playgroud)

但是这给了我'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") };
Run Code Online (Sandbox Code Playgroud)

这会给'join'带来错误:

"错误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"));
Run Code Online (Sandbox Code Playgroud)

我使用foreach循环存储了'query'的结果,如Tim建议的那样:

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);
}
Run Code Online (Sandbox Code Playgroud)

这可以通过一些额外的努力在几个方面进行通用化,但这对我的目的来说已经足够了.

Tim*_*ter 6

Linq应仅用于查询.使用它来查询源并构建您的匿名类型.然后用a foreach来添加DataRows.一般来说:你不能CopyToDataTable用于其他任何事情IEnumerable<DataRow>.这就是匿名类型错误的原因.

(有一种使用反射的解决方法,我一般不会建议:

实现CopyToDataTable<T>通用类型T不是aDataRow)

Imho a foreach是你能做的最好的,因为它非常易读:

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);
}
Run Code Online (Sandbox Code Playgroud)