I’m trying to do some tests with Dynamic Linq at the moment, but being new at it, I am having troubles.
Currently I have one DataTable object that I have filled by an SQL query to a database. Now I want to execute dynamic linq queries on this DataTable. This may seem illogical, but my end goal is be able to perform joins on two different DataTables that are filled by two different databases, so with that in mind I hope it makes more sense.
I’m trying to understand a simpler situation and experiment a bit with it before I go on to solve that main problem.
Question one is that I am not entirely sure about the choice between IQueryable(Of T) and IEnumerable(Of T). The way I understand is that if you do everything in-memory you choose IEnumerable. I would think that fits for my case then, right? However, when I looked at changing the IEnumerable in IQuerbyable (in the code snippet below), I was surprised to see that “x.Item(Fieldname)” does not work!? What am I missing? The error it gave is: “Late Binding operations cannot be converted to an Expression Tree”.
Anyway, lets take a look. I already got part of it working:
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
This seems to work fine. I used the two string variables, because in the end I want to dynamically decide which field to take. So, “x!Description” is not the way to go for me. However, now I wanted to add a projection to the query, i.e. Select a number of columns.My expectation was that this should work like this:
query = query.Select(Of String)(Function(x As Object) x.Item(desc))
(N.B.: I use Select(Of String), because this specific column has that as type. This should of course in the end be dynamically filled too)
However, this fails during runtime on an InvalidCastException: “Unable to cast object of type ‘WhereSelectEnumerableIterator2[System.Data.DataRow,System.String]' to type 'System.Collections.Generic.IEnumerable1[System.Data.DataRow]’.” I dont really understand what happens here; I’m guessing something is wrong because I want to return DataRow’s, but at the moment only select one field, which happens to be a String. Can anyone explain/help me?
Thanks in advance!
OK, EDIT, as I should probably have given some more info from scratch:
I could have a variable number of where- or select-clauses. My idea was I could add these dynamically by looping through the list that contains this information. So I thought I kinda need the .Where() and .Select() functions that IEnumerable offers.
You declare
queryto be of typeIEnumerable(Of DataRow)in the following line:Now, you want to create an
IEnumerable(Of String)with yourSelect, which is fine.But you try to asign the result, which is of type
IEnumerable(Of String), toquery, which is of typeIEnumerable(Of DataRow).And since
IEnumerable(Of String)can’t be cast toIEnumerable(Of DataRow)and vice versa, you get anInvalidCastException.Also, I don’t know why you use
Function(x As Object)in yourWhereandSelect, better useFunction(row As DataRow), since you already know that you are working with aDataRow.Furthermore, your code could be rewritten like this:
Changing
columnToUsewould make you able to select the field you want dynamically.To select more than one field, you need to return a colleciton of Dictionarys, ExpandoObjects or Tuples or something like that.
Example: