LINQ Query based on values in a list? - vb.net

I'm trying to filter the entity based on the possibility of a list of integers being passed to the query; however it is also possible that no integers as passed into the query. In the example below If a "status" is passed in as a list of integers, i would want to return all results that contain a matching status (integer)
Status As List(Of Integer)
Query as IQueryable(Of db.People) = db.people.asNoTracking.Where(Function(C) c.DeleteFlag = False)
Query = (From q In Query From s In Status Where q.PersonStatus = s)

Assuming if you pass in no statuses, that you want all the records, then:
query=db.people.Where(Function(c) c.DeleteFlag=False)
if (Status.Any())
query=query.Where(Function(c) Status.Contains(c.PersonStatus))
If you want no records when no statuses are passed in then:
if (!Status.Any())
query=new List(Of people).AsQueryable()
else
...
endif

Related

Simplified way to find duplicates in list of objects in vb.net and merge them

I have an API that accepts a list of objects(Object contains ProductID and Quantity). I want to determine whether there are duplicate product ID on the passed list. If duplicates are found, I'll merge them by adding the Quantity of duplicate product ID. To do this, I created my own algorithm that loops the list one-by-one then store it to another list (the verified one). The code goes like this.
For Each passedVoucher As VoucherInfo In VouchersToRelease
indexofduplicate = 0
sumQuantity = 0
hasDuplicate = False
If VerifiedReleasedVouchers.Count() > 0 Then
'for loop that checks if productID exists in the VerifiedReleasedVouchers
For Each finalList As VoucherInfo In VerifiedReleasedVouchers
If passedVoucher.ProductID = finalList.ProductID Then
indexofduplicate = VerifiedReleasedVouchers.IndexOf(finalList)
'if true, adds the Quantity of duplicate to the existing quantity at the VerifiedReleasedVouchers
sumQuantity = Convert.ToInt32(VerifiedReleasedVouchers(indexofduplicate).Quantity) + Convert.ToInt32(passedVoucher.Quantity)
VerifiedReleasedVouchers(indexofduplicate).Quantity = sumQuantity.ToString
hasDuplicate = True
Exit For
End If
Next
End If
'adds the voucher to verified released voucher if no duplicate was found
If hasDuplicate = False Then
VerifiedReleasedVouchers.Add(passedVoucher)
End If
Next
So what I did is, I ForEach looped the passed list. Inside the loop, I compared the current object from the passedList into every object in the verifiedList(w/c is empty by default) to determine whether their are duplicate product ID. If no duplicate was found, i'll just add the current object to the verifiedList. If duplicate was found, ill just update the object from the verified list with the same ProductID by storing the sum of the Quantity of both objects.
The code above works perfectly as intended but the thing is, it performs a lot of tasks. Is there any way to simplify what I did above?
P.S. List.Distinct() is not a solution for this
You could use Linq to easily achieve what you want. First you must GroupBy ProductID and then Select all the groups with a sum of the quantity. Finally, we get a list:
Dim VerifiedReleasedVouchers As List(Of VoucherInfo) = VouchersToRelease.GroupBy(Function(x) x.ProductID).[Select](Function(y) New VoucherInfo() With {
.ProductID = y.Key,
.Quantity = y.Sum(Function(z) z.Quantity),
.Denom = y.First().Denom
}).ToList()

Return Table or List with Linq Group By

I have a typed datatable with the columns month and money. My goal is to get an object that I can bind to a dgv (table or list) where the money is grouped by month.
In SQL I would accomplish this with
Select month, sum(money) from table
group by month
I tried (according to this question )
Public Function Get Overview(...)
dim query =
from dt In _dataset.Table.AsEnumerable()
Group By dt.Week
Into Test = Sum(dt.money)
Select Test
Return Test
End Function
I cannot run this but the returntype is IEnumerable(of Double) so to me it looks I do not get the Table or List back that I can bind to my dgv. Could anyone tell me what is wrong with my query?
Edit:
This is Linq to datasets.
Declaration and instance
Privat _dataset as Dataset1
Private _adapter as New Dataset1TableAdapters.Table
_dataset = New Dataset1
_adapter.Fill(_dataset.Table)
With Select Test you explicitly select only the aggregated values of the money column.
Your query should look like:
Dim query = From dt In _dataset.Table.AsEnumerable()
Group By week = dt.Week
Into result = Sum(dt.money)
Note that this yields an IEnumerable(Of ...) of an anynomous type. If you want to use the result outside the current method, create a type that represents this result or use e.g. the Tuple class, like:
Dim query = From dt In _dataset.Table.AsEnumerable()
Group By week = dt.Week
Into result = Sum(dt.money)
Select Tuple.Create(week, result)
This yields an IEnumerable(Of Tuple(Of TheTypeOfWeek, TheTypeOfMoney)) which you can bind to your DGV.

How do I get a field of a datatable when I know column name and a row ID, without looping?

How do I get a field of a datatable when I know column name and a row ID, without looping?
For instance; I want the “Total Sold” value when Region = City and Product = Legos. This is something I have struggled with for a long time, probably because I think in SQL so looping through everything all the time doesn’t always seem like the correct way to go. BUT if I just need to learn to think like a VB developer and always loop to get something out of a list or table, please let me know.
I have a series of asserts comparing two datatables, one that has one row with a named column for each cell (from XML produced by SSRS), and another datatable that has one row for each unique value in a region (produced from a SQL query).
Table from SQL (mockup dataset):
Region Prod Total Sold
City Legos 68
State Legos 90
Nat. Legos 200
City ToyB 20
State ToyB 30
Nat. ToyB 40
City ToyC 450
State ToyC 600
Nat. ToyC 900
Table from XML (dataset returned from SSRS):
City_Legos State_Legos Nat_Legos City_ToyB State_ToyB Nat_ToyB City_ToyC State_ToyC
68 90 200 20 30 40 450 600
The part of the assert statement that gets data from the XML based datatable is easy, because there is only one row (index 0), and I can just name the column I want:
Dim xmlRow As DataRow = xmlDatatable.Rows(0)
Assert.AreEqual(“my SQL cell goes here”, xmlRow.Field(Of Integer)(“City_Legos”))
And I can do one assert for each of the specified columns. Many of the columns won’t be tested, and they have specific names, so I can’t simply loop through the columns. So what do I put in “my SQL cell goes here” to return the Total Sold for City and Legos? Obviously in SQL it would be easy: SELECT TOP 1 Total_Sold WHERE Region = City and Prod = Legos.
I am currently looping through the SQL datatable and testing each cell for my criteria, but that logic gets huge because I have to wrap each like in If…Then, like this:
For Each m As DataRow In mySqlTable.Rows
If m.Field(Of String)("Prod") = "Legos" Then
If m.Field(Of String)("Region") = "City" Then
Assert.AreEqual(m.Field(Of Integer)("TotalSold"), xmlRow.Field(Of Integer)(“City_Legos”))
End If
If m.Field(Of String)("Region") = "State" Then
Assert.AreEqual(m.Field(Of Integer)("TotalSold"), xmlRow.Field(Of Integer)(“State_Legos”))
End If
If m.Field(Of String)("Region") = "Nat" Then
Assert.AreEqual(m.Field(Of Integer)("TotalSold"), xmlRow.Field(Of Integer)(“Nat_Legos”))
End If
End If
Next
I’m hoping I can do something like a select or LINQ or Function?
Something like this would be nice:
Dim result as Integer = mySqlTable.Select.First(“Region = City and Prod = Legos“)
Or:
Assert.AreEqual(mySqlTable.Select.First(“Region = City and Prod = Legos“), xmlRow.Field(Of Integer)(“City_Legos”))
This is a unit test, so I will always know the column and field names returned by SSRS.
Getting the cell by Column name and row identifier has always been something I’ve struggled with, so hopefully I can finally get this solved.
Thanks!
You could use the Datatable Compute method. Replace (“my SQL cell goes here” with
CInt(mySqlTable.Compute("SUM([Total Sold])", "[Region] = 'City' and [Prod] = 'Legos'"))
This is assuming that the rows are unique and no null values.

Creating filter with SQL queries

I am trying to create a filter with SQL queries but am having trouble with numeric values linking to other tables.
Every time I try to link to another table, it takes the same record and repeats it for every element in the other table.
For example, here is query:
SELECT ELEMENTS.RID,TAXONOMIES.SHORT_DESCRIPTION,[type],ELEMENT_NAME,ELEMENT_ID,SUBSTITUTION_GROUPS.DESCRIPTION,namespace_prefix,datatype_localname
FROM ELEMENTS,SUBSTITUTION_GROUPS,TAXONOMIES,SCHEMAS,DATA_TYPES
WHERE ELEMENTS.TAXONOMY_ID = TAXONOMIES.RID AND ELEMENTS.ELEMENT_SCHEMA_ID = SCHEMAS.RID AND
ELEMENTS.DATA_TYPE_ID = DATA_TYPES.RID
AND ELEMENTS.SUBSTITUTION_GROUP_ID = 0
The last line is the actual filtering criteria.
Here is an example result:
There should only be ONE result (Item has an RID of 0). But it's repeating a copy of the one record for every result inside the substitution groups table (there's 4).
Here is my database schema for reference. The lines indicate relationships between tables and the circles indicate the values I want:
You're forgot to join between ELEMENTS and SUBSTITUTION_GROUPS in your query.
SELECT
ELEMENTS.RID,TAXONOMIES.SHORT_DESCRIPTION,[type],ELEMENT_NAME,ELEMENT_ID,SUBSTITUTION_GROUPS.DESCRIPTION,namespace_prefix,datatype_localname
FROM
ELEMENTS,SUBSTITUTION_GROUPS,TAXONOMIES,SCHEMAS,DATA_TYPES
WHERE
ELEMENTS.TAXONOMY_ID = TAXONOMIES.RID AND ELEMENTS.ELEMENT_SCHEMA_ID = SCHEMAS.RID
AND ELEMENTS.DATA_TYPE_ID = DATA_TYPES.RID
AND ELEMENTS.SUBSTITUTION_GROUP_ID = SUBSTITUTION_GROUPS.RID
AND ELEMENTS.SUBSTITUTION_GROUP_ID = 0

Compare two rows in AND condition

just having a problem using the AND operator in SQL as it returns a zero result set.
I have the following table structure:
idcompany, cloudid, cloudkey, idsearchfield, type, userValue
Now I execute the following statement:
SELECT *
FROM filter_view
WHERE
(idsearchfield = 4 and compareResearch(userValue,200) = true)
AND (idsearchfield = 6 and compareResearch(userValue,1) = true)
compareResearch ist just a function that casts the userValue and compares it to the other value and returns true if the value is equal or greater. UserValue is actually stored as a string (that's a decision made 6 years ago)
Okay, I get a zero resultset which is because both criterias in braces () are AND combined and one row can only have one idsearchfield and therefor one of the criterias won't match.
How do I get around this? I NEED the AND Comparison, but it won't work out this way.
I hope my problem is obvious :-)
If you've recognised that both conditions can't ever both be true, in what way can the AND comparison be the correct one?
select *
from filter_view
where (idsearchfield = 4 and compareResearch(userValue,200) = true)
OR (idsearchfield = 6 and compareResearch(userValue,1) = true)
This will return 2 rows (or more). Or are you looking for some way to correlate these two rows so that they appear as a single row?
Okay, so making a tonne of assumptions, because you haven't included enough information in your question.
filter_view returns a number of columns, one of which is some form of record identifier (lets call that ID). It also includes the aforementioned idsearchfield and userValue columns.
What you actually want to find is those id values, for which one row of filter_view has idsearchfield = 4 and compareResearch(userValue,200) = true and another row of filter_view has idsearchfield = 6 and compareResearch(userValue,1) = true
The general term for this is "relational division". In this simple case, and assuming that id/idsearchfield are unique in this view, we can answer it with:
select id,COUNT(*)
from filter_view
where (idsearchfield = 4 and compareResearch(userValue,200) = true)
OR (idsearchfield = 6 and compareResearch(userValue,1) = true)
group by id
having COUNT(*) = 2
If this doesn't answer your question, you're going to have to add more info to your question, including sample data, and expected results.