在使用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();
这是我尝试过的...... 我不知道如何建立&#39;查询&#39;以某种方式允许我使用它。 尝试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") };
但是这给了我这个错误的查询.CopyToDataTable()&#39;:
&#34;错误1类型&#39; AnonymousType#1&#39;不能用作类型参数 &#39; T&#39;在泛型类型或方法中 &#39; System.Data.DataTableExtensions.CopyToDataTable(System.Collections.Generic.IEnumerable)&#39 ;. 匿名类型#1&#39;没有隐式参考转换。至 &#39;的System.Data.DataRow&#39;&#34;
据我猜测,这个错误是因为选择了新的&#39;没有将DataRows构建到&#39; query&#39;中,.CopyToDataTable()要求;它只是建立匿名记录。此外,我不知道如何将查询元素强制转换为DataRow,因为&#34;由于保护级别而无法访问#34;
尝试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") };
这会在&#39; join&#39;:
上出错&#34;错误5无法隐式转换类型 &#39; System.Collections.Generic.IEnumerable&#39;至 &#39; System.Collections.Generic.IEnumerable&#39 ;.一个 存在显式转换(您是否错过了演员?)&#34;
另一方面,如果我发表评论,请加入&#39;子句(以及&#39;选择&#39;中的相应dt2列),我在&#39;选择&#39;:
上收到此错误&#34;错误2无法隐式转换类型 &#39; System.Data.EnumerableRowCollection&#39;至 &#39; System.Collections.Generic.IEnumerable&#39 ;.一个 存在显式转换(您是否错过了演员?)&#34;
我还尝试使用列预先定义DataTable3,以便选择&#39; select&#39;条款是一个真正的DataRow,但我仍然无法选择&#39;选择&#39;利用它。
编辑,细节,解决方案: 谢谢蒂姆的帮助。我选择了尝试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"));
我存储了来自&#39;查询&#39;的结果。使用Tim建议的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);
}
这可以通过一些额外的努力在一些方面进行通用化,但这对我的目的来说已经足够了。
答案 0 :(得分:6)
Linq应仅用于查询。使用它来查询源并构建您的匿名类型。然后使用foreach
添加DataRows
。一般情况下:除了CopyToDataTable
之外,您不能将IEnumerable<DataRow>
用于其他任何内容。这就是匿名类型错误的原因。
(有一种使用反射的解决方法,我一般不会建议:
Implement CopyToDataTable<T>
Where the Generic Type T
Is Not a DataRow
)
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);
}
答案 1 :(得分: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);