select count on list using linq on specific value vb.net - vb.net

I am having an issue getting the results I am looking for. What I need to do is essentially:
Select count(invoicenbr) from invoicelist where invoicenbr = 'invoice'
but when I try it in linq I am not getting the correct results.
When I try to execute the linq query below, it gives me the count for the entire list, and not for the where invoicenbr = 'invoice'...
Here is my linq query that is returning the count for the entire invoiceList:
Dim test = (From invoices In invoicelist _
Where e.Row.Cells("invoicenbr").Value = invoice).count()

You have a naming issue in your code, i assume that it's responsible for your problem.
The variable in your query is invoices but later you use invoice to compare it with the cell value, so you have a different variable in scope with name invoice.
This should work:
Dim invoicenbr As String = e.Row.Cells("invoicenbr").Value
Dim duplicates = From invoice In invoicelist
Where invoice = invoicenbr
Dim duplicateCount As Int32 = duplicates.Count()

Related

Check if ArrayList contains an object with a property that equals a specific value

So I have an application in VB.net that is pulling data from a table and inserting it into an arraylist to be used later. What I want to do is before adding the object to the arraylist, I want to check that arraylist to see if the object exists, but I want to be able to check based off a particular property of that object.
Here is an example of what I am talking about:
Lets say Im pulling info from a table with the following columns:
InvoiceNo|DateCharged|Quantity|TotalCharge
I have a SQL statement that pulls info from a table and then I use a data reader to go through the info. My Code looks somewhat like this:
Dim dbobjM As New clsDbobjManual()
If dbobjM.Exec_SQL_DR("SELECT InvoiceNo, DateCharged, Quantity, TotalCharges From Invoices") = 0 Then
If dbobjM.DataReader.HasRows Then
Dim invoicelist As New ArrayList(5000)
Dim invoiceno As String = String.Empty
Do While dbobjM.DataReader.Read()
invoicelist.Add(New Invoice(dbobjM.DataReader.GetInt32(0), dbobjM.DataReader.Value(1), dbobjM.DataReader.GetInt32(2), dbobjM.DataReader.GetFloat(3)))
Loop
End If
End if
(Exec_SQL_DR is a function in the clsDbobjManual class that check to make sure the SQL is in the proper syntax first and checks that records are returned otherwise it returns an error)
Basically what I want to do is before I add a new object to the arraylist I want to check if an object already exists in the list where the InvoiceNo is a particular value, or the value pulled from the table each time to make sure there is no duplicates. I want one object in the list for each InvoiceNo.
Im looking for something like:
If Not invoicelist.Contains(Object where InvoiceNo = dbobjM.DataReader.GetInt32(0)) Then
invoicelist.Add
End If
But I cant seem to find what I need, any help is greatly appreciated
There is no need to use the outdated ArrayList: a List will serve you better. Please see ArrayList vs List<> in C# if you need reasons - the advantages for a list apply to VB.NET too.
Without seeing your clsDbobjManual or Invoice classes, I ended up writing the minimal code to do what you're after, which is basically the check for invoices.Any(Function(i) i.InvoiceNo = inv.InvoiceNo), which you can do if you have the data in a List(Of Invoice).
Please note that I assumed that the appropriate data types have been used in the database - you should use the Decimal type for money as otherwise you can end up with significant rounding errors, and a date should be stored as DateTime, not as a string.
Imports System.Data.SqlClient
Module Module1
Class Invoice
Property InvoiceNo As Integer
Property DateCharged As DateTime
Property Quantity As Integer
Property TotalCharges As Decimal
Sub New()
' empty constructor
End Sub
Sub New(invoiceNo As Integer, dateCharged As DateTime, quantity As Integer, totalCharges As Decimal)
Me.InvoiceNo = invoiceNo
Me.DateCharged = dateCharged
Me.Quantity = quantity
Me.TotalCharges = totalCharges
End Sub
End Class
Function LoadData() As List(Of Invoice)
Dim invoices As New List(Of Invoice)
Dim connStr As String = "your connection string"
Dim sql = "SELECT InvoiceNo, DateCharged, Quantity, TotalCharges From Invoices"
Using sqlConn As New SqlConnection(connStr)
Using sqlCmd As New SqlCommand(sql, sqlConn)
Dim reader As SqlDataReader = sqlCmd.ExecuteReader()
While reader.Read()
Dim inv As New Invoice(reader.GetInt32(0), reader.GetDateTime(1), reader.GetInt32(2), reader.GetDecimal(3))
If Not (invoices.Any(Function(i) i.InvoiceNo = inv.InvoiceNo)) Then
invoices.Add(inv)
Else
' there is a duplicate invoice number
End If
End While
End Using
End Using
Return invoices
End Function
Sub Main()
Dim uniqueInvoices As List(Of Invoice) = LoadData()
' uniqueInvoices now contains the data
End Sub
End Module
If you had a lot of invoice entries to go through, you would likely be better off writing an SQL query to do that.
If you actually just want to find duplicate invoice numbers, you could use the SQL
SELECT [InvoiceNo]
FROM testTable
GROUP BY [InvoiceNo]
HAVING COUNT([InvoiceNo]) > 1
Finally, please ensure that you are using Option Strict On so that you don't make accidental data type errors - they can drastically slow down your program and lead to erroneous results.
You can use linq to select the objects that matches your condition.
Dim result = (From invoiceitem As Invoice
In invoicelist
Where invoiceitem.InvoiceNo = dbobjM.DataReader.GetInt32(0)
Select invoiceitem).ToList()
If Not result.Count > 0 Then
invoicelist.Add(New Invoice(dbobjM.DataReader.GetInt32(0), dbobjM.DataReader.Value(1), dbobjM.DataReader.GetInt32(2), dbobjM.DataReader.GetFloat(3)))
End If

Distinct ComboBox Items

I am trying to convert sql to entity and I need to select distinct items. I thought this would work but its returning all the rows instead of the distinct items.
Dim OrderNos = (From r In Orders.R3Delivery Where r.mainOrderNumber <> "" Select r).Distinct().ToList()
For Each thisentry In OrderNos
cbOrderNumbers.DisplayMember = thisentry.mainOrderNumber
cbOrderNumbers.ValueMember = thisentry.mainOrderNumber
Next
Also is their any good free sql to linq tools out their linquer good but its like 60 quid
The problem is that the Distinct() is comparing the entire object being returned, not just the order number.
If you only need the order numbers, changing this line should get you there:
Dim OrderNos = (From r
In Orders.R3Delivery
Where r.mainOrderNumber <> ""
Select r.mainOrderNumber).Distinct().ToList()
If you need the whole object, then it gets more complicated.

Error when using linq on datatable

I am trying to run the following code converting my datatable to be usable in linq all seems fines and compiles but when I Execute the statement I get the following statement i get the error below new entires just has location and ordernumber in the return values I have to do it this way as I am supporting a legacy access 97 system thanks.
Dim total = From row In newEntries.AsEnumerable()
Select row.Field(Of Int32)("location") Distinct
retVal = Convert.ToInt32(total)
This is my whole code but im still getting an invalid type cast error their is data exsits for this order by teh way
Dim retVal As Int32
Dim newEntries As New DataTable
Dim script As String = scriptBuilder.GetDistinctOrdersForLocations(OrderNumber)
newEntries = connection.SqlSelectToDataTable(script)
Dim total = From row In newEntries.AsEnumerable()
Select row.Field(Of Int32)("location") Distinct
retVal = total.Count()
If you want the count of the collection just do this:
retVal = total.Count()
this will return the count from the distinct query that you have written.
Just to clarify, #David B identified the data type of location was int16 not int32, so changing this in the linq query resolved the issue.
Your LINQ query is returning a collection. You should use something like First or FirstOrDefault.
I'm a little rusty on VB LINQ, but try :
retVal = Convert.ToInt32(total.First())
Note: This will throw an error if there are no items in the collection.
It's important to understand when you write a LINQ query and assign it to a variable, that variable essentially contains a query object, and not the results of running the query. In order to get the value that results from the query, you need to call some method on the query object such as:
total.Single() ' Assumes you expect the query to return exactly one result.
I changed the code to int16 worked here is the code for any one else stuck thanks #Ric
Dim retVal As Int32
Dim newEntries As New DataTable
Dim script As String = scriptBuilder.GetDistinctOrdersForLocations(OrderNumber)
newEntries = connection.SqlSelectToDataTable(script)
Dim total = From row In newEntries.AsEnumerable()
Select row.Field(Of Int16)("location") Distinct
retVal = total.Count()

VB.NET & Linq: Sum datatable column and Group by date in another column

I have a typedDataset (ds) and its datatable(dt). The datatable has the columns Date(ttmmyyy) and Worktime. I want to sum the Worktime by month. I already accomplished to sum the Worktime with
Dim sum = dt.AsEnumerable().Sum((Function(x) x.Worktime))
I need help with group this by month.
I created a table with your fields and the following query worked nice:
Dim query = From row In dt
Group row By VarDate= row.Field(Of DateTime)("Date") Into MonthGroup = Group
Select New With {
Key VarDate,
.Worktime = MonthGroup.Sum(Function(r) r.Field(Of Int32)("Worktime"))
}
Used variable VarDate because Date is reserved for it's own class.
Output:
Vardate: 10/15/2013 Worktime: 150
Vardate: 10/16/2013 Worktime: 180
EDIT:
To get the output just use:
For Each obj In query
Dim datet = obj.VarDate
Dim WorkH = obj.Worktime
Next
To avoid declarying types when using linq, insert the line: option infer on on the very first line of the vb.net document ( so you can use dim datet = obj.Vardate ) without declaring the type. It is like var in c#

Sum from LINQ query

Cannot get this to work. Want to get the sum of all the amounts int the database from the following LINQ statement:
Dim currentPaid = From a In db.Payments
Where a.ForJob = id
Select a.Amount
Dim totalPaid As Double = currentPaid.Sum()
As it underlines the second statment and says:
Overload resolution failed because no accessible 'Sum' accepts this number of attributes.
Asked another question with code and someone answered my question exactly so the answer is below:
Dim totalPaid = db.Payments.Where(Function(a) a.ForJob = jobId).Sum(Function(a) a.Amount)
Dim sum = (From a In db.Payments Where a.ForJob = id Select a.Amount).Sum();