Linq to Datarow,选择多列作为不同的列?

3

我基本上是想将以下的MSSQL查询转换为LINQ:

SELECT DISTINCT [TABLENAME], [COLUMNNAME] FROM [DATATABLE]

我最接近的是
Dim query = (From row As DataRow In ds.Tables("DATATABLE").Rows _
                  Select row("COLUMNNAME") ,row("TABLENAME").Distinct

当我执行上述操作时,出现了错误

范围变量名称只能从不带参数的简单或限定名称中推断出。

我有点期望它会返回一个集合,我可以遍历并为每个条目执行操作。也许是DataRow集合?

作为一个完全的LINQ新手,我不确定我错过了什么。我尝试过各种变化:

Select new with { row("COLUMNNAME") ,row("TABLENAME")}

并获取:

仅从没有参数的简单或限定名称中推断匿名类型成员名称。

为了解决这个问题,我尝试过:

 Dim query = From r In ds.Tables("DATATABLE").AsEnumerable _
        Select New String(1) {r("TABLENAME"), r("COLUMNNAME")} Distinct

然而,它似乎没有正确地执行独特的任务。

另外,有人知道一些好的书籍/资源可以帮助提高流畅度吗?

4个回答

6
你开始在数据表对象上使用LINQ,对dt.AsEnumerable进行查询,它会返回一个DataRow对象的IEnumerable集合。
Dim query = From row As DataRow In ds.Tables("DATATABLE").AsEnumerable _
              Select row("COLUMNNAME") ,row("TABLENAME")

你可能想说row("COLUMNNAME").ToString()等等。查询最终将成为一个具有2个字符串属性的匿名类型的IEnumerable; 这是你想要的吗?你可能需要指定属性的名称;我不认为编译器会推断它们。
Dim query = From row As DataRow In ds.Tables("DATATABLE").AsEnumerable _
              Select .ColumnName = row("COLUMNNAME"), .TableName = row("TABLENAME")

这假设在你的原始SQL查询中,你使用ADO获取了这个数据集,并确保你的结果是不同的。
常见的混淆因素:
一个关键点是Linq-to-SQL和(通常称为)LINQ-to-Dataset的Linq-to-object活动是两个非常不同的东西。在两者中都可以看到使用LINQ,所以经常会引起混淆。
LINQ-to-Dataset是:
1. 以与往常一样的方式获取您的datatable,使用数据适配器和连接等,最终得到传统的datatable对象。然后,您不再像以前那样迭代行,而是:
2. 运行针对dt.AsEnumerable的linq查询,它是datarow对象的IEnumerable。
Linq-to-dataset选择使用传统的ADO.NET而非Linq-to-SQL,但是一旦你有了datatable,就使用LINQ(-to-object)来检索/排列/过滤数据,而不是过去6年我们一直在做的方式。我经常这样做。我喜欢我的常规ado sql(使用我开发的工具),但LINQ很棒
LINQ-to-SQL是一个不同的东西,在幕后发生着非常不同的事情。在LINQ-To-SQL中,你:
1. 使用Visual Studio中的工具定义与数据库匹配的模式,从而获得与模式匹配的简单实体对象。 2. 使用db上下文编写linq查询,并将这些实体作为结果返回。
在幕后,在运行时,.NET将这些LINQ查询转换为SQL并将它们发送到数据库,然后将返回的数据转换为你在模式中定义的实体对象。
其他资源:

那是一个相当简略的总结。要进一步了解这两个非常不同的事情,请查看:
LINQ-to-SQL
LINQ-to-Dataset

关于LINQ的一本绝佳书籍是LINQ in Action,作者是Fabrice Marguerie、Steve Eichert和Jim Wooley(Manning)。去买吧!正是你需要的。非常好。LINQ不是昙花一现,值得买一本书来学习。在.NET中有太多要学习的东西,但是掌握LINQ所花费的时间是值得的。


1

我想我已经弄清楚了。 感谢您的帮助。

也许有更简单的方法吗?

我所做的是

Dim comp As StringArrayComparer = New StringArrayComparer
Dim query = (From r In ds.Tables("DATATABLE").AsEnumerable _
        Select New String(1) {r("TABLENAME"), r("COLUMNNAME")}).Distinct(comp)

这将返回一个新的字符串数组(2个元素),使用自定义比较器运行

Public Class StringArrayComparer
    Implements IEqualityComparer(Of String())

    Public Shadows Function Equals(ByVal x() As String, ByVal y() As String) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of String()).Equals

        Dim retVal As Boolean = True

        For i As Integer = 0 To x.Length - 1
            If x(i) = y(i) And retVal Then
                retVal = True

            Else
                retVal = False
            End If

        Next

        Return retVal

    End Function

    Public Shadows Function GetHashCode(ByVal obj() As String) As Integer Implements System.Collections.Generic.IEqualityComparer(Of String()).GetHashCode

    End Function
End Class

0

谢谢,我已经基本上超越了里面的大部分内容。至少在这方面是这样。 - Beta033

0

我有同样的问题,从我学习LINQ和IEnumerables的各种片段中,以下方法对我有效:

Dim query = (From row As DataRow In ds.Tables("DATATABLE").Rows _
              Select row!COLUMNNAME, row!TABLENAME).Distinct

奇怪的是,使用旧的VB感叹号(!)语法消除了"Range variable name..."错误但关键区别在于在查询结果(IEnumerable)对象上使用.Distinct方法而不是尝试在查询中使用Distinct关键字。

然后,此LINQ查询返回一个匿名类型的IEnumerable集合,其属性与DataRow中选择的列匹配,因此以下代码随后可访问:

For Each result In query
   Msgbox(result.TABLENAME & "." & result.COLUMNNAME)
Next

希望这能帮助到其他遇到这个问题的人...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接