【问题标题】:Linq join select all columns and CopyToDataTableLinq join 选择所有列和 CopyToDataTable
【发布时间】:2017-10-04 19:26:40
【问题描述】:

TABLE SCHEMA 我在解决 linq 到数据集的查询时遇到问题;我必须在两个数据表之间进行简单的左连接,但我事先不知道数据表 B 中的确切列数(A,B,C ...?)所以我想选择所有列;我找到了以下链接

select-all-columns-after-join-in-linq

select-all-columns-for-all-tables-in-join-linq-join

        Dim Query = From A In TableA _
                    Join B In TableB _
                    On A("COD") Equals B("COD") _
                    Select New With {A, B}
        Dim TableC As DataTable = Query.CopyToDataTable()

我也试过了

Select New With {.DAT = A.ItemArray.Concat(P.ItemArray).ToArray()}).ToList

还有更多,但我未能将查询结果带入新数据表;我收到类型转换错误,或者我不明白如何将两个单独表中提供的查询结果合并到一个数据表中。

【问题讨论】:

  • 您希望在datatable 两列A("COD")B("COD") 中发生什么?
  • 没什么,只是为了不在 [Select New With {.....] 语句中放入要从表 B 中选择的各个列,因为我无法确定表中存在多少列B,我不会使用动态 linq(所以我决定模糊地选择所有列)请参阅 TABLE SCHEMA
  • 所以您的 TABLE SCHEMA 显示列 COD 两次,但这在 DataTable 中是不允许的。
  • true,有一种简单的方法可以避免重复 COD 列,并且仍然将表 B 中的所有剩余列捆绑在一起,甚至事先不知道列的名称?在表 B 上,我表示 A B C,但它可以是 L M N O 或任何其他序列

标签: vb.net linq join datatable


【解决方案1】:

创建一些扩展方法并使用反射将满足您的需求,尽管这可能不是解决您的问题的理想方法(通常,反射永远不会)。

Public Module SomeExt
<System.Runtime.CompilerServices.Extension()>
Public Function GetTypedValue(Of TProp)(ByVal p As PropertyInfo, obj As Object) As TProp
    Return DirectCast(p.GetValue(obj), TProp)
End Function

<System.Runtime.CompilerServices.Extension()>
Public Function FlattenToDataTable(Of T)(src As IEnumerable(Of T)) As DataTable
    Dim ans = New DataTable()

    Dim srcdtpis = GetType(T).GetProperties().Cast(Of PropertyInfo)().ToList()
    For Each aDT As DataTable In srcdtpis.Select(Function(pi) pi.GetTypedValue(Of DataRow)(src.First()).Table)
        For Each col In aDT.Columns.Cast(Of DataColumn)()
            ans.Columns.Add(col.ColumnName, col.DataType)
        Next
    Next

    For Each drs In src
        Dim newDR = ans.NewRow
        For Each aDR In srcdtpis.Select(Function(pi) pi.GetTypedValue(Of DataRow)(drs))
            For Each colname In aDR.Table.Columns.Cast(Of DataColumn)().Select(Function(dc) dc.ColumnName)
                newDR(colname) = aDR(colname)
            Next
        Next
        ans.Rows.Add(newDR)
    Next

    Return ans
End Function
End Module

你可以这样使用它:

Dim Query = From A In TableA.AsEnumerable() _
                Join B In TableB.AsEnumerable() _
                On A("COD") Equals B("COD") _
                Select New With {A, B}
Dim TableC As DataTable = Query.FlattenToDataTable()

请注意,重复的列名将设置为最后一个 DataTable 的值。

【讨论】:

  • 太棒了;当您还输入了如何使用该功能时,噩梦就结束了;唯一的问题是,当它尝试创建 COD 列两次时会引发错误;我解决了如下更改行 [If Not (ans.Columns.Contains(col.ColumnName)) Then ans.Columns.Add(col.ColumnName, col.DataType)] 。谢谢
  • 我没有想到 Add 会导致问题 - 我修改了数据行分配,因此它只会覆盖重复项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多