Min Max in LInq with VB.NET - vb.net

I am needing help to using LINQ expressions under VB.NET.
I have a Class with 3 fields, I want to find the MIN and MAX of the COMBINED 3 fields (think SQL UNION). I have been able to cobble-up a LINQ expression that puts all 3 (decimal) fields into 1 (decimal) field... and it "should" be as easy as specifying the .Min or .Max property at the end of the expression... however, it keeps throwing an error for me... so, looking for some help.
Here is the LINQ expressions in VB.NET that returns a LIST of the UNION'd columns/fields...
Dim result As List(Of RValue) = MeterRoughnessMaster_R1.[Select](Function(x) New RValue() With { _
.RValue = x.RValueBOTH _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New RValue() With { _
.RValue = x.RValueUP _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New RValue() With { _
.RValue = x.RValueDN _
}))).ToList
The above needs to be re-worked so that "result" should hold a decimal value or MIN or MAX.
I tried this...
Dim result = MeterRoughnessMaster_R1.[Select](Function(x) New With { _
.RValue = x.RValueBOTH _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New With { _
.RValue = x.RValueUP _
}).Union(MeterRoughnessMaster_R1.[Select](Function(x) New With { _
.RValue = x.RValueDN _
}))).Min
But it error'd with "At least one object must implement IComparable." so, I am missing a keyword someplace that would otherwise invoke IComparable (which is what I thought .Min would do)
I want above LINQ expression re-worked to simply return .Min (or .Max) to the variable "result" (decimal). The "RValue" Class can be abandoned if necessary... but the 3 fields from "MeterRoughnessMaster_R1" must remain. I want to do this in LINQ (VB.NET).

There's no need for that elaborate Union. You should be using SelectMany.
Dim allValues = MeterRoughnessMaster_R1.SelectMany(Function(x) {x.RValueBOTH, x.RValueUP, x.RValueDN}).ToArray()
Dim min = allValues.Min()
Dim max = allValues.Max()
Obviously you don't have to use the allValues variable and can get the min or max in one statement but you should use a variable if you want both.
EDIT: I should also note that if you do use a single statement to get just the min or just the max then you can drop the ToArray call too.
Dim min = MeterRoughnessMaster_R1.SelectMany(Function(x) {x.RValueBOTH, x.RValueUP, x.RValueDN}).Min()
Dim max = MeterRoughnessMaster_R1.SelectMany(Function(x) {x.RValueBOTH, x.RValueUP, x.RValueDN}).Max()

Related

VB Running grouped LINQ into DataTable

I'm trying to run a LINQ to datatable, that normally works for me. This time I'm trying something new to me, Grouping and taking the first row from each group. questionGroups is of type IEnumerable(Of Object). When I open the query in the debugger I see a collection of DataRows, each with an ItemArray of the values I expect in the columns. How do I run this query to a DataTable, or select the two columns I want and run those into a Dictionary?
Public member 'ToTable' on type 'WhereSelectEnumerableIterator(Of
VB$AnonymousType_0(Of Object,IEnumerable(Of Object)),Object)' not
found.
Dim answerGroup As String = "QuestionSortKey"
Dim answerNo As String = "AnswerNo"
Dim surveyDefinitionNo As String = "Pk_SurveyDefinitionNo"
Dim query = _
From rows In surveyAnswerKeys.Rows _
Where rows(answerNo) IsNot Nothing _
Order By Guid.NewGuid() _
Group By questionSortKey = rows(answerGroup) _
Into questionGroups = Group _
Select questionGroups.First()
Dim randomAnswerNos As DataTable = query.ToTable
Edit: This question is an offshoot of this one: VB LINQ - Take one random row from each group

Group and sum list (vb.net)

I've got a list of objects
Class Bundledtellingen
Property tTimestamp As String
Property tValue As Double
End Class
Now I am trying to group this list by tTimestamp and sum tValue. By searching similar questions it was clear the best way to go is using Linq. I've put this together:
Dim query = bundledlist.GroupBy( _
Function(telling) telling.tTimestamp, _
Function(telling) telling.tTimestamp, _
Function(ts, values) New With _
{.Key = ts, _
.Sum = values.Sum()} _
)
Using writer As StreamWriter = New StreamWriter("C:\test.txt")
For Each result In query
writer.WriteLine(result.Key & " " & result.Sum)
Next
End Using
As far as I can tell by looking at the examples at http://msdn.microsoft.com/en-us/library/bb534493.aspx#Y0 this should work, though i get the following exception: "Overload resolution failed because no accessible 'Sum' accepts this number of arguments."
You've specified one unnecessary parameter into your GroupBy call. Thy that one:
Dim query = bundledlist.GroupBy( _
Function(telling) telling.tTimestamp, _
Function(ts, values) New With _
{.Key = ts, _
.Sum = values.Sum()} _
)
The first one is key selector, the second is result selector.
Your call with 3 parameters has additional value selector, where you're selecting Function(telling) telling.tTimestamp twice - once for Key and once for Value. That's why your Sum didn't work: you tried call Sum on telling.tTimestamp.

JQGrid on ASP.Net MVC with VB.Net

I am trying to make a JQGrid for a simple table.
After following through with a VB translated version from
http://haacked.com/archive/2009/04/14/using-jquery-grid-with-asp.net-mvc.aspx
from
http://www.qa.downappz.com/questions/jqgrid-sorting-in-vb-net-mvc-app.html
I modified it to my own database and came up with this function
Public Function SelectGridData(ByVal sidx As String, ByVal sord As String, ByVal page As Integer, ByVal rows As Integer) As ActionResult
Dim context As New IssueDBEntities
Dim pageIndex As Integer = Convert.ToInt32(page) - 1
Dim pageSize As Integer = rows
Dim totalRecords As Integer = context.Issues.Count()
Dim totalPages As Integer = CInt(Math.Ceiling(CSng(totalRecords) / CSng(pageSize)))
Dim jsonData = New With { _
.total = totalPages, _
.page = page, _
.records = totalRecords, _
.rows = (From p In context.Issues _
Order By (p.ID & " " & sord) _
Select New With {.id = p.ID, .cell = _
{p.ID, p.Image_Path, p.Magazine_Type,p.Magazine_Path}}).ToArray()}
Return Json(jsonData, JsonRequestBehavior.AllowGet)
End Function
The grid does show up without any data, and the system throws an error
The error description says
"Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types."
Any help is appreciated, if this is due to some basic misunderstanding, please guide me, I am willing to do some hard work.
Thank you
Edit: The code that finally worked as per Oleg's Suggestion
Dim Simple_Object As IQueryable(Of Object)
Dim Second_Simple_Object As IQueryable(Of Object)
Dim My_Array As Array
Dim My_Second_Array As Array
Simple_Object = From p In Context.Issues _
Order By (p.ID & " " & sord) _
Select New With {p.ID, p.Image_Path, p.Magazine_Type, p.Magazine_Path}
My_Array = Simple_Object.ToArray()
Second_Simple_Object = From p In Context.Issues _
Order By (p.ID & " " & sord) _
Select New With {p.ID}
My_Second_Array = Second_Simple_Object.ToArray()
Dim My_Result(0) As My_Record_Type
For i = 0 To My_Array.GetLength(0) - 1
If i > 0 Then
ReDim Preserve My_Result(i)
End If
My_Result(i) = New My_Record_Type
My_Result(i).id = CInt(My_Second_Array(i).ID)
My_Result(i).Cell = {My_Array(i).ID.ToString, My_Array(i).Image_Path.ToString, _
My_Array(i).Magazine_Type.ToString, My_Array(i).Magazine_Path.ToString}
Next
Class My_Record_Type
Public id As Integer
Public Cell As String()
End Class
You try to fill rows property in one step. The problem is that you use Entity Framework which have some restrictions in the conversion of the data types. You can solve the problem if you first make query to get the items which you need without any data conversion and save intermediate results as List of items. After that you can make another LINQ Query where you include explicit conversion of p.ID to string. Moreover your current code don't use any paging of data. So the user will never seen more as the first page if you don't use loadonce: true.
It's difficult for me to write correct code in VB without debugging it. I use C# instead since last years. I recommend you to look at the answer for more information. It contains implementation of the server side filtering. If you don't need it and remove the corresponding code the rest code will be very short and I hope it will be easy to understand.
Here is complete sample of JQgrid with ASP.NET MVC 3 + C# (you can convert it to vb.net)
http://www.dotnetacademy.blogspot.in/2012/04/using-jqgrid-in-aspnet-mvc-3.html

Linq to SQL Cast Exception

I'm starting my first Linq to SQL project in VB.NET (which I am also new to).
I am trying to Delete an entity but am having trouble with an InvalidCastException. The debugger breaks at the Next statement in the ForEach loop.
My entity class is called Material.
Any help would be very much appreciated.
Thanks,
Kenneth
Dim materialsTable As Table(Of Material) _
= (New DataContext("Server=.\SQLEXPRESS; Database=Materials; Trusted_Connection=yes;") _
.GetTable(Of Material)())
Dim materialsToDelete = (From x In materialsTable _
Where x.MaterialName = aMaterial.MaterialName _
Select x)
If (materialsToDelete Is Nothing) Then Return
If (materialsToDelete.Count = 0) Then Return
For Each m As Material In materialsToDelete
materialsTable.DeleteOnSubmit(m)
Next
materialsTable.Context.SubmitChanges()
Make sure you actually run the query with a .ToList()
Also, go with a straightforward DataContext if you can. I've not seen your implementation of the DC anywhere.
Dim db as new NorthwindDataContext()
Dim materialsToDelete = (From x In db.Materials _
Where x.MaterialName = aMaterial.MaterialName _
Select x)
You actually don't need to loop to delete them.
materialsTable.DeleteAllOnSubmit(materialsToDelete)
materialsTable.Context.SubmitChanges()

Linq to object: ToList can not convert to generic list

Dim tenItem = From t In _InvalidFeeList _
From i In ItemCount _
Where t.FeeCode <> i.FeeCode _
Order By t.Description _
Ascending Take (10)
Dim feeList As List(Of AccessorialFee) = tenItem.ToList()
I am getting "Can not convert to System.generic.list" error. I look all over for this error and it seem like my code should work for example here
I don't get it. Can someone tell me where i got it wrong?
edit: I think i should explain what I'm trying to do here. I want to compare two object list and select the object from the InvalidFeeList if the FeeCode is not equal to the object in ItemCount FeeCode and take the first 10 objects from the InvalidFeeList.
The problem is that you've got two "From" clauses, so the result isn't just the type of the original collection. It's easy to fix though - just add a projection at the end:
Dim tenItem = From t In _InvalidFeeList _
From i In ItemCount _
Where t.FeeCode <> i.FeeCode _
Order By t.Description _
Ascending Take (10) _
Select t ' This is the new line '
Dim feeList As List(Of AccessorialFee) = tenItem.ToList()
EDIT: Are you trying to find items in _InvalidFeeList whose FeeCode isn't present in any item in ItemCount? If so, I suggest this change:
Dim feeCodes = From i In ItemCount Select i.FeeCode
Dim feeCodeSet = new HashSet(Of FeeCodeType)(feeCodes)
Dim tenItem = From t in _InvalidFeeList
Where Not feeCodeSet.Contains(t.FeeCode)
Order By t.Description _
Ascending Take (10)
Dim feeList As List(Of AccessorialFee) = tenItem.ToList()
As you can see, I didn't know the type of FeeCode, and VB is not exactly my strong point, but I hope you get the general idea. This suggestion is assuming you're using LINQ to Objects - if you're using LINQ to SQL I'm not sure of the best way to do it. Note that we no longer need the Select clause for tenItem as we're only dealing with a single collection now.
_InvalidFeeList is not of type List(Of AccessorialFee)
[Edit] Try this and add a breakpoint and a watch:
Dim tenItem = (From t In _InvalidFeeList _
From i In ItemCount _
Where t.FeeCode <> i.FeeCode _
Order By t.Description _
Ascending Take (10)).ToList().GetType()