How do I extract a value from a Linq IQueryable object? - vb.net

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 [...]

Related

Linq Query in VB

Good Day,
I am querying my database using Linq and I have run into a problem, the query searched a column for a search phrase and based on if the column has the phrase, it then returns the results, The query is below,
Dim pdb = New ProductDataContext()
Dim query =
From a In pdb.tblUSSeries
Join b In pdb.tblSizes_ On a.Series Equals b.Series
Where
a.Series.ToString().Equals(searchString) Or
b.Description.Contains(searchString) Or Not b.Description.Contains(Nothing)
Order By b.Series, b.OrderCode Ascending
Select New CustomSearch With
{
.Series = a.Series,
.SeriesDescription= a.Description,
.Coolant = a.Coolant,
.Material = a.Material,
.Standard = a.Standard,
.Surface = a.Surface,
.Type = a.Type,
.PointAngle = a.PointAngle,
.DiaRange = a.DiaRange,
.Shank = b.Shank,
.Flutes = b.Flutes,
.EDPNum = b.EDPNum,
.SizesDescription = b.Description,
.OrderCode = b.OrderCode
}
Return query
I think the problem is that, in the table certain rows are NULL, so when it is checking the column for the phrase and it encounters a row that is null it, breaks and returns this error,
The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
I have ran this query against another column that has all the rows populated with data and it returns the results ok.
So my question is how can I write it in VB to query the db with the supplied searchstring and return the results, when some of the rows in the columns have null values.
Any help would be great.
The exception occurs when you make the projection (i.e. select new CustomSearch)
And yes your trying to assign Null to some int property
(Not sure which one of your properties that is)
one of 2 choices :
1) Use nullalbe types for your properties (or just that one property).
2) project with an inline If ( ?? in C#) , I don't know VB so don't catch me on the syntax.
Taking Series just as an example i don't know if it's an int or if that's the problematic property
Select New CustomSearch With
{
.Series = If(a.Series Is Nothing,0, CInt(a.Series))
}
In C#
Select new CustomSearch
{
Series = a.Series ?? 0;
}

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

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.

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));

Operator '=' is not defined for types 'Integer' and 'IQueryable(Of Integer)'

This is giving me a headache. I have this link query here that grabs an ID
Dim mclassID = From x In db.SchoolClasses Where x.VisitDateID = _visitdateID Select x.ClassID
And then later on I have this linq query
ViewData("Staff") = From t In db.Staffs Where t.ClassID = mclassID Select t
Any help would be much appreciated. I've tried quite a few things but to no avail. I've attempted casting, converting, Is operand, etc.
The problem is that myClassID is an anonymous IQueryable. You need to force it into another type (List is my favorite), and then pull it out of that type. So if you were to select it into a List(Of Integer) you could then extract the First() one since it would be the only. You could try something like this:
Dim myClassIDList As List(Of Integer) = New List(Of Integer)( _
From x In db.SchoolClasses Where x.VisitDateID = _visitdateID Select x.ClassID)
Dim myClassID as Integer = myClassIDList.First()
Just a guess, but would it help to wrap the right-side of the equation in parenthesis? I.e.:
ViewData("Staff") = (From t In db.Staffs Where t.ClassID = mclassID Select t)
Using the Select operator, you can have multiple results returned. If you are only expecting one result (i.e. you are selecting by a primary key), then you can use Single or SingleOrDefault (depending on whether there is guaranteed to be a result) to get just that one.
Dim mclassID = (From x In db.SchoolClasses _
Where x.VisitDateID = _visitdateID _
Select x.ClassID).SingleOrDefault()
You should change this
Dim mclassID = From x In db.SchoolClasses Where x.VisitDateID = _visitdateID Select x.ClassID
to select a single instance or the first instance, otherwise it does as its reporting, returning an IEnumerable, which causes your error later.
Or you could change your second statement to something like
ViewData("Staff") = From t In db.Staffs Where mclassID.Contains(t.ClassID) Select t
taking advantage of the mclassID as an IEnumerable of int.
You can see the errors in Output if you set appropriate options: -
Navigate VS2010 menus to Tools/Options/Projects and solutions/Build and Run/
Set MSBuild Project build output verbosity to "Detailed"
I had a similar error that wasn't showing in the Error list, but with this options setting I saw: -
error BC30452: Operator '=' is not defined for types 'System.Nullable(Of Integer)' and 'Integer'.
from this statement: -
If tqGDBChart.UserIsGroupAdmin(Userid, Groupid) = 0 Then 'User is not a group admin for this group
Easily fixed it with an intermediate variable.
Dim GroupAdminCount As Integer = tqGDBChart.UserIsGroupAdmin(Userid, Groupid)
If GroupAdminCount = 0 Then 'User is not a group admin for this group
have you tried:
ViewData("Staff") = From t In db.Staffs Where t.ClassID.equals(mclassID) Select t