动态Linq查询 - 如何构建select子句?

Mar*_*tao 5 linq vb.net dynamic vb.net-2010

我正在尝试使用Dynamic Linq进行一些测试,但是对它不熟悉,我遇到了麻烦.

目前我有一个DataTable对象,我已经通过SQL查询填充到数据库.现在我想在这个DataTable上执行动态linq查询.这可能看起来不合逻辑,但我的最终目标是能够在由两个不同数据库填充的两个不同的DataTable上执行连接,所以考虑到这一点,我希望它更有意义.在我继续解决这个主要问题之前,我正在尝试理解一个更简单的情况并进行一些实验.

问题一是我不完全确定IQueryable(Of T)和IEnumerable(Of T)之间的选择.我理解的方式是,如果你在内存中做所有事情,你选择IEnumerable.我认为那适合我的情况,对吗?但是,当我看到更改IQuerbyable中的IEnumerable时(在下面的代码片段中),我惊讶地发现"x.Item(Fieldname)"不起作用!?我错过了什么?它给出的错误是:"后期绑定操作无法转换为表达式树".

无论如何,让我们来看看.我已经有部分工作了:

    Dim desc As String = "Description"
    Dim status As String = "Status"

    Dim query As IEnumerable(Of DataRow) = From x In tab.AsEnumerable()
    query = query.Where(Function(x As Object) x.Item(status) < 100)

    For Each row As DataRow In query.ToList()
    'Do something
    Next row
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常.我使用了两个字符串变量,因为最后我想动态决定采用哪个字段.所以,"x!描述"不适合我.但是,现在我想在查询中添加一个投影,即选择一些列.我的期望是这应该是这样的:

query = query.Select(Of String)(Function(x As Object) x.Item(desc))
Run Code Online (Sandbox Code Playgroud)

(注意:我使用Select(Of String),因为这个特定的列具有类型.这当然也应该动态填充)

但是,在InvalidCastException运行时期间失败:"无法转换类型为'WhereSelectEnumerableIterator 2[System.Data.DataRow,System.String]' to type 'System.Collections.Generic.IEnumerable1 [System.Data.DataRow]'的对象." 我真的不明白这里发生了什么; 我猜错了,因为我想返回DataRow,但目前只选择一个字段,恰好是一个字符串.谁能解释/帮助我?

提前致谢!

好的,编辑,因为我应该从头开始提供更多信息:我可以有一个可变数量的where-或select-clauses.我的想法是我可以通过循环包含此信息的列表来动态添加这些.所以我认为我需要IEnumerable提供的.Where()和.Select()函数.

slo*_*oth 3

您在以下行中声明query其类型:IEnumerable(Of DataRow)

Dim query As IEnumerable(Of DataRow) = From x In tab.AsEnumerable()
Run Code Online (Sandbox Code Playgroud)

现在,您想IEnumerable(Of String)用您的 来创建一个Select,这很好。

但是您尝试将类型为 的结果分配IEnumerable(Of String)query类型为 的结果IEnumerable(Of DataRow)

query = query.Select(Of String)(Function(x As Object) x.Item(desc))
Run Code Online (Sandbox Code Playgroud)

由于IEnumerable(Of String)无法转换为IEnumerable(Of DataRow),反之亦然,因此您会得到一个InvalidCastException.


另外,我不知道你为什么Function(x As Object)在你的Whereand中使用Select,更好地使用Function(row As DataRow),因为你已经知道你正在使用 a DataRow

此外,您的代码可以这样重写:

Dim desc As String = "Description"
Dim status As String = "Status"

Dim columnToUse = status

Dim query = From x In tab.AsEnumerable()
            Where x.Item(status) < 100
            Select x(columnToUse)

For Each item as String In query.ToList()
    'Do something
Next 
Run Code Online (Sandbox Code Playgroud)

更改columnToUse将使您能够动态选择所需的字段。

要选择多个字段,您需要返回字典、ExpandoObjects 或元组或类似内容的集合。

例子:

Dim columnToUse = new String() {desc, status} ' select columns dynamically

Dim query = tab.AsEnumerable().Where(Function(row) row.Item(status) < 100)

' Selecting dynamically
Dim result1 = query.Select(function(row) columnToUse.ToDictionary(function(c) c, function(c) row(c)))
Dim result2 = query.Select(Function(row)
                                Dim exp As IDictionary(Of String, Object) = new ExpandoObject()
                                For Each column in columnToUse
                                    exp(column) = row(column)
                                Next
                                return exp
                            End Function)
Run Code Online (Sandbox Code Playgroud)