Select Max Date items in group using Linq VB.NET - vb.net

I have data as shown.
NameA Date
NameA Date
NameA Date
NameB Date
NameB Date
NameC Date
NameD Date
NameD Date
I would like to have it returned as below only getting the record with the most recent date. I am confused on the syntax of the Linq, which i started below, but am unsure as where to go with it.
NameA Date
NameB Date
NameC Date
NameD Date
Started Linq
Dim pciLST = _
From p As SmartFormData(Of PCISF) In pciSFM.GetList(m_Criteria) _
Where p.SmartForm.EmployeeUsername.ToLower() = m_Username.ToLower() AndAlso _
IsOpen(p.SmartForm.CompletedDate, p.SmartForm.ActiveFor, p.SmartForm.Open)
ANSWER
Dim pciLST = _
From g In pciSFM.GetList(m_Criteria).AsEnumerable() _
Where g.SmartForm.EmployeeUsername.ToLower() = m_Username.ToLower() _
Order By (g.SmartForm.CompletedDate) Descending _
Take 1 _
Select _
Name = IIf(g.SmartForm.FormName Is Nothing, "", g.SmartForm.FormName.ToString()), _
DateSigned = IIf(g.SmartForm.CompletedDate IsNot Nothing AndAlso _
Date.TryParse(g.SmartForm.CompletedDate, New Date()), g.SmartForm.CompletedDate, New Date(1, 1, 1)), _
ActiveFor = IIf(g.SmartForm.ActiveFor Is Nothing, -1, Integer.Parse(g.SmartForm.ActiveFor)), _
NewLink = IIf(g.SmartForm.NewLink Is Nothing, "", g.SmartForm.NewLink.ToString()), _
ViewLink = IIf(g.SmartForm.ViewLink Is Nothing, "", g.SmartForm.ViewLink.ToString()), _
Open = IIf(g.SmartForm.Open Is Nothing, -1, Integer.Parse(g.SmartForm.Open)), _
Requirement = IIf(g.SmartForm.Requirement Is Nothing, "", g.SmartForm.Requirement.ToString()), _
Archived = Boolean.Parse(g.SmartForm.Archived), _
Id = Long.Parse(g.Content.Id), _
Due = GetDue(Date.Parse(g.SmartForm.CompletedDate), Integer.Parse(g.SmartForm.ActiveFor))
Return pciLST.AsQueryable()

This code is working now
public class NameDate
Public Name As String
Public D As DateTime
End Class
. . . . .
Dim list As New List(Of NameDate)(4)
list.Add(New NameDate() With {.Name = "A", .D = DateTime.Now.AddDays(-10)})
list.Add(New NameDate() With {.Name = "A", .D = DateTime.Now})
list.Add(New NameDate() With {.Name = "B", .D = DateTime.Now.AddDays(-10)})
list.Add(New NameDate() With {.Name = "B", .D = DateTime.Now.AddDays(-20)})
Dim o = From nd In list _
Group nd By nd.Name Into g = Group _
Select New NameDate() With {.Name = g.First().Name, .D = g.Max(Function(x) x.D)}
o.ToList().ForEach(Sub(x) Debug.WriteLine(x.Name & " - - " & x.D.ToString()))
Here is original c#
var o = from nd in list
group nd by nd.Name
into g
select new NameDate() {Name = g.Key, Date = g.Max(d => d.Date)};

Related

Linq query to array

This is currently my Linq query:
result = From d In dc.Tracker
Where d.Responsible.Value = "first last name"
Order By d.Priority1, d.Deadline
Select New With { _
Key .Title = d.Name, _
Key .Description = d.Priority1, _
Key .Priority2= d.Priority2, _
Key .Status = d.Status, _
Key .Resp= d.Resp, _
Key .Deadline = d.Deadline, _
Key .Notes = d.Notes, _
}
I am trying to output the data but can only seem to do so doing this:
For Each d In result
Console.WriteLine(d)
Next
But i can not seem to place it into an array so that i can call it like this:
result(0), result(1), etc etc...
Or even better:
result.Title, result.Description, etc etc...
How can i change that linq into an array?
Use the .ToArray() method.
result = (From d In dc.Tracker
Where d.Responsible.Value = "first last name"
Order By d.Priority1, d.Deadline
Select New With { _
.Title = d.Name, _
.Description = d.Priority1, _
.Priority2= d.Priority2, _
.Status = d.Status, _
.Resp= d.Resp, _
.Deadline = d.Deadline, _
.Notes = d.Notes}).ToArray()
Got it working at least how i am needing it too:
Dim Title As New ArrayList
Dim Description As New ArrayList
Dim Priority2 As New ArrayList
Dim Status As New ArrayList
Dim Resp As New ArrayList
Dim Deadline As New ArrayList
Dim Notes As New ArrayList
result = From d In dc.Tracker
Where d.Responsible.Value = "first last name"
Order By d.Priority1, d.Deadline
Select New With { _
Key .Title = d.Name, _
Key .Description = d.Priority1, _
Key .Priority2= d.Priority2, _
Key .Status = d.Status, _
Key .Resp= d.Resp, _
Key .Deadline = d.Deadline, _
Key .Notes = d.Notes, _
}
For Each d In result
If Not IsNothing(d.Title()) Then Title.Add(d.Title()) Else Title.Add("NA")
If Not IsNothing(d.Description()) Then Description.Add(d.Description().value) Else Description.Add("NA")
If Not IsNothing(d.Priority2()) Then Cost.Add(d.Priority2().value) Else Priority2.Add("NA")
If Not IsNothing(d.Status()) Then Status.Add(d.Status().value) Else Status.Add("NA")
If Not IsNothing(d.Resp()) Then Responsible.Add(d.Resp().value) Else Resp.Add("NA")
If Not IsNothing(d.Deadline()) Then Deadline.Add(d.Deadline()) Else Deadline.Add("NA")
If Not IsNothing(d.Notes()) Then Notes.Add(d.Notes()) Else Notes.Add("NA")
Next

Group By LINQ Dyanmic Query

I am trying to allow the user to change the query dynamically by a querystring parameter. I am having trouble getting the group by to work in vb.net. I am wanting to return the id, name, and count of each group.
' load all of the types
Dim baseQuery = db.Answers _
.Where(Function(a) a.Question.CorrectAnswer <> a.answer) _
.Where(Function(a) a.Question.TypeId = TypeId)
If catId <> 0 Then
baseQuery = baseQuery _
.Where(Function(x) x.Question.CategoryId = catId) _
.ToList()
End If
If approachId <> 0 Then
baseQuery = baseQuery _
.Where(Function(x) x.ApproachId = approachId) _
.ToList()
End If
Dim grouppedQuestionTypesincorrectTotal = baseQuery _
.GroupBy(Function(x) x.Question.TypeId) _
.Select(Function(x) New With {.id = x.id}) _
.ToList()
Dim grouppedCategorieincorrectTotal = baseQuery _
.GroupBy(Function(x) x.Question.CategoryId) _
.ToList()
Dim grouppedApproachesincorrectTotal = baseQuery _
.GroupBy(Function(x) x.ApproachId) _
.ToList()
ViewBag.QuestionTypes = grouppedQuestionTypesincorrectTotal
ViewBag.Categories = grouppedCategorieincorrectTotal
ViewBag.Approaches = grouppedApproachesincorrectTotal

'Order by' ignored in LINQ query

I am trying to sort a list by company name. I have tried the following code but this sorts the list by CompID and not CoShort. How should I change this to sort by CoShort?
Public Shared Function [SelectCompanyData](iElement() As Integer) As List(Of CompanyList)
Dim db As New EntryDataContext()
Dim q As IQueryable(Of CompanyList) = (From Act_Sub_Manfu_Link In db.Act_Sub_Manfu_Links _
Join Company In db.Companies _
On Act_Sub_Manfu_Link.CompID Equals Company.CompID _
Where iElement.Contains(Act_Sub_Manfu_Link.ACCN) _
And Company.In_Dir _
Select New CompanyList With { _
.CompID = Company.CompID, _
.InDir = Company.In_Dir, _
.CoShort = Company.CoShort _
}).Distinct
q.OrderBy(Function(c) c.CoShort)
Dim list As List(Of CompanyList) = q.ToList
Return list
End Function
You have to assign ordered collection into a variable:
Dim oq As IOrderedQueryable(Of CompanyList) = q.OrderBy(Function(c) c.CoShort)
And use it to get List of results:
Dim list As List(Of CompanyList) = oq.ToList()
Doesn't need to be assigned to anything but the return value
Public Function SelectCompanyData(iElement() As Integer) As List(Of CompanyList)
Dim db As New EntryDataContext()
Return (From Act_Sub_Manfu_Link In db.Act_Sub_Manfu_Links _
Join Company In db.Companies _
On Act_Sub_Manfu_Link.CompID Equals Company.CompID _
Where iElement.Contains(Act_Sub_Manfu_Link.ACCN) _
And Company.In_Dir _
Select New CompanyList With { _
.CompID = Company.CompID, _
.InDir = Company.In_Dir, _
.CoShort = Company.CoShort _
}).Distinct().OrderBy(Function(c) c.CoShort).ToList()
End Function

How to union two LINQ queries (WhereSelectEnumerableIterator) error

I am trying to build aKendo bar chart. I need the number of tickets opened, and tickets closed. I need that result grouped by month. Here is my LINQ
Dim openTickets = (From t In queue _
Where _
(t.CreateDate.Year = Convert.ToDateTime(DateTime.Now).Year)
Group t By _
ID = CType(t.CreateDate.Month, Integer), _
Month = CType(t.CreateDate.ToString("MMMM"), String) _
Into g = Group _
Select New With _
{.Month = Month.Substring(0, 3), .Opened = g.Where(Function(t) t.CreateDate.Month = ID).Count(Function(t) t.Id)})
Dim closedTickets = (From t In queue _
Where _
(t.CloseDate.Year = Convert.ToDateTime(DateTime.Now).Year)
Group t By _
ID = CType(t.CloseDate.Month, Integer), _
Month = CType(t.CloseDate.ToString("MMMM"), String) _
Into g = Group _
Select New With _
{.Month = Month.Substring(0, 3), .Closed = g.Where(Function(t) t.CloseDate.Month = ID).Count(Function(t) t.Id)})
Dim ticketCount = openTickets.Union(closedTickets)
When I try this, I get "WhereSelectEnumerableIterator". If I change the second query so that the name is ".Opened" and not ".Closed" it works, but then I do not know my count for "closed".
Ultimately I am trying to get an output of an array to supply the chart... similar to this:
[{"Month":"Apr","Opened":138,"Closed":150}
INSTEAD OF
[{"Month":"Apr","Opened":138,"Closed":0},{"Month":"Apr","Opened":0,"Closed":150}
You need to use a Join statement to merge the two and keep the values distinct. Something like this:
Dim tickets = From open In openTickets _
Join closed In closedTickets _
On open.Month Equals closed.Month _
Select New With _
{.Month = open.Month, .Opened = open.Opened, .Closed = closed.Closed}

How to use the vb equivalent of ++ for an index property in a Linq query projecting a new type

I'd normally do this in C# but since I've got to get this code in this particular assembly which is a vb.net one, I'm stuck.
Here's my linq query:
Dim i As Integer = 0
Dim oldAndCurrentIntersectionOnNames = From currentApplicant In currentApplicants _
Group Join oldApplicant In oldApplicants _
On _
New With {Key .FirstName = currentApplicant.FirstName, _
Key .LastName = currentApplicant.LastName} _
Equals _
New With {Key .FirstName = oldApplicant.FirstName, _
Key .LastName = oldApplicant.LastName} Into applicants = Group _
From applicant In applicants.DefaultIfEmpty(New ApplicantNameDetails()) _
Select New ApplicantNameDetails() With _
{ _
.Index = i+=1, _
.FirstName = CStr(IIf(Not currentApplicant.FirstName Is Nothing, currentApplicant.FirstName, Nothing)), _
.OldFirstName = CStr(IIf(Not applicant.FirstName Is Nothing, applicant.FirstName, Nothing)), _
.LastName = CStr(IIf(Not currentApplicant.LastName Is Nothing, currentApplicant.LastName, Nothing)), _
.OldLastName = CStr(IIf(Not applicant.LastName Is Nothing, applicant.LastName, Nothing)) _
}
You'll see the .Index = i+=1
This was my attempt to do what I'd quite happily do in C# (i.e. Index = i++) in VB. Unfortunately the VB compiler doesn't like that.
Has anybody got any suggestions as to how I'd do this in VB.
Thanks in advance
Essentially, you can’t. If you want the Linq query to get consecutive values, use a special (so-called “generator”) class that has an IncrementAndGet (or simply Next) method for your integer.
class IntegerGenerator
private state as integer = 0
public function Next() as integer
dim oldState = state
state += 1
return oldState
end function
end class
There is an overload of the Select method that lets you use the index of the item on the result collection. http://msdn.microsoft.com/en-us/library/bb534869.aspx
You could split your query in two parts to use it (untested)
Dim q = From currentApplicant In currentApplicants _
Group Join oldApplicant In oldApplicants On _
New With {Key.FirstName = currentApplicant.FirstName, _
Key.LastName = currentApplicant.LastName} _
Equals _
New With {Key.FirstName = oldApplicant.FirstName, _
Key.LastName = oldApplicant.LastName} Into applicants = Group _
From applicant In applicants.DefaultIfEmpty(New ApplicantNameDetails())
Dim oldAndCurrentIntersectionOnNames = _
q.Select(Function(x, i) New ApplicantNameDetails() With _
{ _
.Index = i, _
.FirstName = CStr(IIf(Not x.currentApplicant.FirstName Is Nothing, x.currentApplicant.FirstName, Nothing)), _
.OldFirstName = CStr(IIf(Not x.applicant.FirstName Is Nothing, x.applicant.FirstName, Nothing)), _
.LastName = CStr(IIf(Not x.currentApplicant.LastName Is Nothing, x.currentApplicant.LastName, Nothing)), _
.OldLastName = CStr(IIf(Not x.applicant.LastName Is Nothing, x.applicant.LastName, Nothing)) _
})