LINQ Statement in VB.Net - What is it doing? - vb.net

I'm trying to understand what this LINQ statement is actually doing. I have no experience in LINQ, so I'm trying to get somewhat of a "plain english" translation.
MyDataTable contains the following data:
OrderByValues, Contract, PayType, PayAmount
Dim groupIDs = From r In myds.MyDataTable Select OBV = r.Item("OrderByValues"), PT = r.Item("PayType"), Contract = r("Contract") Distinct
For Each r in groupIDS
a = r.OBV
b = r.PT
c = r.Contract
Next
I'm not sure if there is enough info here to help you out or not. I'd appreciate any help.
Thanks.

The first line creates an query that will hold a collection of anonymous types. The query is not executed yet because of LINQ's deferred execution. This can be broken down into pieces:
From r In myds.MyDataTable defines r as an individual element of the IEnumerable (usually array or List)) myds.MyDataTable
Select OBV = r.Item("OrderByValues"), ... Distinct creates an anonymous type with properties called OBV, PT, Contract and assigns those properties values from the element r.
The foreach loop actually executes the query and creates the IEnumerable to iterate over. Then within this loop, it repeatedly sets a,b,c to the properties of the anonymous type defined in the query. This does seem a bit strange, since the variables a,b,c will only remember the last value set to them.
More reading on LINQ.

It selects all "OrderByValues", "PayType", and "Contract" columns from your datatable, ignoring duplicate rows.
It then iterates over the resultset, and assigns the 3 values to the variables "a", "b", and "c" respectively.

Related

LINQ Select Syntax VB.NET

I have a list of Tuples I am trying to run a Select and Where query on to return a list of Objects from the Tuple.Item5 parameter. In my where clause I am looking to match Tuple.Item4 to a local variable.
I'm not sure what the VB.NET syntax is for the Select portion, I only know the c# syntax.
Essentially I am trying to select Tuple.Item5 from my list of tuples where Tuple.Item4 = sCurID. I'm unsure as to what should go in the Select section although in c# I believe it would be Select(t => t.Item5)
This is what I have:
listObj = listTuples.Select( Unsure What Goes Here ).Where(Function(w) w.Item4 = sCurID)
Once you apply the Select in C# or VB, you have reduced the Tuple to the Item5 value and can't access Item4. Do the Select last:
Dim listObj = listTuples.Where(Function(t) t.Item4 = sCurId).Select(Function(t) t.Item5)
listObj = listTuples.Select(Function(t) t.Item5).Where(Function(w) w.Item4 = sCurID).ToList()

How do I extract a value from a Linq IQueryable object?

I am new to Linq and have been stumped for several days. I have searched this and several other boards to find the answer but cannot. I have a Linq query that is returning 1 value of int.
Public Function myV()
Dim MR As New MainEntities()
Dim mV = From AspNetUsers In MR.AspNetUsers
Where Context.User.Identity.Name() = AspNetUsers.Email.ToString Select AspNetUsers.VB
Return mV
End Function
If myV = 1 Then
perform other code
End If
But when I try to compare to an Int it says the object cannot be compared. I have tried to convert the IQueryable(of Interger) to Int and cannot. How do I get to the Interger value in the IQueryable object?
The LINQ statement returns an IEnumerable, which is like an array in that it can hold multiple values, even it only happens to have one value in it.
The best way to return a single value is .First(), or .Single() if you want to throw an exception if more than one value exists. (Which one you choose depends on your context.)
Public Function myV()
Dim MR As New MainEntities()
Dim mV = From AspNetUsers In MR.AspNetUsers
Where Context.User.Identity.Name() = AspNetUsers.Email.ToString Select AspNetUsers.VB.First()
Return mV
End Function
Because mV is an IQueryable, you can consider it as a type of list or an array. So you need to get the first value:
If myV.First() = 1 Then
'...
End If
Or more likely you want to do that inside the mV function:
Dim mV = From AspNetUsers In MR.AspNetUsers
Where Context.User.Identity.Name() = AspNetUsers.Email.ToString
Select AspNetUsers.VB
Return mV.First()
You misunderstood the query. Your LINQ executes a SQL Statement that is the follows:
SELECT AspNetUsers.VB
FROM AspNetUsers
WHERE ApsNetUsers.Email = "here the name"
Therefore the query does not return only one VB but a table consisting of one column and multiple rows.
In order to retrieve the first value you have to call .First()
If myV.First() = 1 Then [...]

Using contains in Linq query produces error

I have a pretty straight forward query that is producing this error at runtime: Only arguments that can be evaluated on the client are supported for the String.Contains method.
The query is supposed to find only the categories that have transfers assigned to them. The transfers can be listed in several categories so there is no table relationship. The Categoryidhash contains data like "7~34~25~42~47". I just realized while writing this that searching for '7' will return multiple results, "7" & '47' Etc. Thats ok i'll just change id's to all double digits. meanwhile...
How can I fix this?
Private Function GetCategoryList() As List(Of Category)
Dim lst As List(Of Category) = New List(Of Category)
Using db As New IPCDataDataContext
lst = (From c In db.Categories
From t In db.Transfers
Where t.CategoryIDhash.Contains(c.ID.ToString)
Select c).ToList()
Return lst
End Using
End Function
The exception means that Contains only accepts arguments that can be converted to fixed variable in SQL. So something like Where t.CategoryIDhash.Contains(someVariable.ToString) would be possible, because someVariable.ToString can be evaluated client-side.
I don't really understand this restriction, because in SQL it is perfectly possible to use a LIKE clause with a string that is built in the SQL statement itself. This is demonstrated by the statement that fixes your problem:
lst = (From c In db.Categories
From t In db.Transfers
Where SqlMethods.Like(t.CategoryIDhash, "%" + c.ID.ToString "%")
Select c).ToList()
This generates (and executes) SQL like
...
WHERE [t1].[CategoryIDhash] LIKE (#p0 + (CONVERT(NVarChar,[t0].[ID]))) + #p1
(where #p0 and #p1 are the % characters.
Although you could do this, I wonder if you're on the right track by using this CategoryIDhash. I think you should convert it to a FK relationship (if it's in your hands to modify the database).

How to get Distinct Values from List(Of T) using Linq

I have a List(Of Hardware) - the List is called HWModels
Class Hardware has the following Properties:
ModelName
Status
CPUStatus
MemoryStatus
DiskStatus
The List is populated by reading a CSV file, once it's populated, I want to return the distinct records based on the ModelName
I've attempted by doing it as follows:
(From a In HWModels Select a.ModelName).Distinct
But this isn't right because I end up with a list of only the ModelName's and nothing else.
How do I get the Distinct function to return all of the other class members within the list?
LINQ to Objects doesn't provide anything to do "distinct by a projection" neatly. You could group by the name and then take the first element in each group, but that's pretty ugly.
My MoreLINQ provides a DistinctBy method though - in C# you'd use:
var distinct = HWModels.DistinctBy(x => x.ModelName).ToList();
Presumably the VB would be something like
Dim distinct = HWModels.DistinctBy(Function(x) x.ModelName).ToList
Apologies for any syntax errors though :(
This will group your objects by the preferred property and then will select the first of each one, removing duplicates.
Dim newlist = HWModels.GroupBy(Function(x) x.ModelName).Select(Function(x) x.First).ToList

checking if all the items in list occur in another list using linq

I am stuck with a problem here. I am trying to compare items in a list to another list with much more items using linq.
For example:
list 1: 10,15,20
list 2: 10,13,14,15,20,30,45,54,67,87
I should get TRUE if all the items in list 1 occur in list 2. So the example above should return TRUE
Like you can see I can't use sequenceEquals
Any ideas?
EDIT:
list2 is actually not a list it is a column in sql thas has following values:
<id>673</id><id>698</id><id>735</id><id>1118</id><id>1120</id><id>25353</id>.
in linq I did the following queries thanks to Jon Skeets help:
var query = from e in db
where e.taxonomy_parent_id == 722
select e.taxonomy_item_id;
query is IQueryable of longs at this moment
var query2 = from e in db
where query.Contains(e.taxonomy_item_id)
where !lsTaxIDstring.Except(e.taxonomy_ids.Replace("<id>", "")
.Replace("</id>", "")
.Split(',').ToList())
.Any()
select e.taxonomy_item_id;
But now I am getting the error Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator.
How about:
if (!list1.Except(list2).Any())
That's about the simplest approach I can think of. You could explicitly create sets etc if you want:
HashSet<int> set2 = new HashSet<int>(list2);
if (!list1.Any(x => set2.Contains(x)))
but I'd expect that to pretty much be the implementation of Except anyway.
This should be what you want:
!list1.Except(list2).Any()
var result = list1.All(i => list2.Any(i2 => i2 == i));