PredicateBuilder + Join + VB.NET - vb.net

I have a db that contains 3 tables
Products Table Suppliers Table Categories Table
Id Id Id
ProductName SupplierName CategoryName
Quantity . .
SupplierId . .
CategoryId
.
.
I am using PredicateBuilder to select Product accoring to the selected product field (Quantity,Productname...)
How Can I use PredicateBuilder or any other method to Select the Product according to Its Suppliername or Categoryname
Please I am using VB.NET I saw many C# examples but I can not understand it nor translate it
I am thinking of using join in predicateBuilder but I do not how !!!!
To be more clear What I want is to combine multiple field in one search ,Like for example:
Give me a Product where It's Name contains "s" and Quantity <10 and SupplierName is Kimo
Give me a product where i's name contains "g" only
give me the products for categoryName "Machines"
.
.
And this search predicate is changable because Each Products table has many fields ,So the search is dynamic according to selected fields
Waiting for your kind help.
I think Arion answer was correct but It needs some revision
AnyWay I came up with this solution ,It is not the most effecient one but It solved my problem.
Dim SupplierAlso As String = ""
Dim CategoryAlso As String = ""
Dim pred = PredicateBuilder.True(Of Products)()
Select Case Entry
Case "Number"
Dim Inum = Entry
pred = pred.And(Function(m As products) m.ID.Equals(CInt(Inum)))
Case "ProductName"
Dim IName = Entry
pred = pred.And(Function(m As Products) m.ProductName.IndexOf(IName, StringComparison.OrdinalIgnoreCase) >= 0)
.
.
.
Case "Supplier"
SupplierAlso = Entry
Case "Category"
CategoryAlso = Ent
Next
Dim f As ProductsDataTable = Products.Product
Dim tmp As IEnumerable(Of Products) = New ProductsDataTable().AsEnumerable()
tmp = f.AsEnumerable.Where(pred.Compile)
Dim qry
If CategoryAlso = "" And SupplierAlso = "" Then
q = (From prods In tmp
Join Cats In Categories
On prods.CategoryId Equals Cats.ID
Join Supps In Suppliers
On Supps.ID Equals prods.SupplierId
Select Supps.SupplierName, Cats.CategoryName, prods.ID _
, prods.ProductName, prods.UnitPrice, prods.CategoryId _
, prods.SupplierId, prods.Location, _
prods.Description, prods.SellPrice, prods.CountInStock _
, prods.ProductionDate, prods.ExpiryDate, _
prods.ProductType, prods.ProductSeason).ToList
ElseIf CategoryAlso <> "" And SupplierAlso <> "" Then
q = (From prods In tmp
Join Cats In Categories
On prods.CategoryId Equals Cats.ID
Join Supps In Suppliers
On Supps.ID Equals prods.SupplierId
Where Cats.CategoryName.IndexOf((CategoryAlso)
, StringComparison.OrdinalIgnoreCase) >= 0 And _ Supps.SupplierName.IndexOf((SupplierAlso), _
StringComparison.OrdinalIgnoreCase) >= 0
Select Supps.SupplierName, Cats.CategoryName, prods.ID, _
prods.ProductName, prods.UnitPrice, prods.CategoryId, _
prods.SupplierId, prods.Location, _
prods.Description, prods.SellPrice, prods.CountInStock, _
prods.ProductionDate, prods.ExpiryDate, _
prods.ProductType, prods.ProductSeason).ToList
ElseIf SupplierAlso <> "" And CategoryAlso = "" Then
q = (From prods In tmp
Join Cats In Categories
On Cats.ID Equals prods.CategoryId
Join Supps In Suppliers
On prods.SupplierId Equals Supps.ID Where _
Supps.SupplierName.IndexOf((SupplierAlso), _
StringComparison.OrdinalIgnoreCase) >= 0
Select Cats.CategoryName, Supps.SupplierName, prods.ID, _
prods.ProductName, prods.UnitPrice, prods.CategoryId, _
prods.SupplierId, prods.Location, _
prods.Description, prods.SellPrice, prods.CountInStock, _
prods.ProductionDate, prods.ExpiryDate, _
prods.ProductType, prods.ProductSeason).ToList
ElseIf CategoryAlso <> "" And SupplierAlso = "" Then
q = (From prods In tmp
Join Cats In Categories
On prods.CategoryId Equals Cats.ID Where Cats.CategoryName.IndexOf _
((CategoryAlso), StringComparison.OrdinalIgnoreCase) >= 0
Join Supps In Suppliers On Supps.ID Equals prods.SupplierId
Select Supps.SupplierName, Cats.CategoryName, prods.ID, _
prods.ProductName, prods.UnitPrice, prods.CategoryId, _
prods.SupplierId, prods.Location, _
prods.Description, prods.SellPrice, prods.CountInStock, _
prods.ProductionDate, prods.ExpiryDate, _
prods.ProductType, prods.ProductSeason).ToList
End If
For Each it In q
With it
DataGridView2.Rows.Add _
({.ID, .ProductName, .UnitPrice, .categoryname, .suppliername, .Location, _
.Description, .SellPrice, .CountInStock, _ .ProductionDate, .ExpiryDate, _
.ProductType, .ProductSeason})
End With
Next
So what do you think ,Is there a better way? Ofcourse yes?Silly question ,But Where?

So i would do something like this then. I have simplify the where statements but I think you will get my point:
dim checkCategoryName as boolean=true
dim checkSupplier as boolean=true
dim checkQuantity as boolean=true
dim query= db.Products.Select (function(p) p)
if checkCategoryName then
query=query _
.Where (function(p) db.Categories.Where (function(c) c.CategoryName="??" ) _
.Select (function(c) c.Id) _
.Contains(p.CategoryId))
end if
if checkSupplier then
query=query _
.Where (function(q) db.Suppliers.Where (function(s) s.SupplierName="??") _
.Select (function(s) s.Id) _
.Contains(q.SupplierId))
end if
if checkQuantity then
query=query.Where (function(q) q.Quantity<10)
end if
dim result=query.ToList()
Where db is the linq data context.

Related

How to remove only one row among duplicate rows in a datatable

I've a datatable dtPackageTest with following rows in it
testid testname
------ -----------
1 abc
2 xyz
1 abc
2 xyz
I followed this answer to but it removes all the duplicate rows, and my expected output is
testid testname
------ -----------
1 abc
2 xyz
My code:
Dim tblDups = From r In dtPackageTest _
Group By Dups = New With {Key .testid = CInt(r("testid")), Key .test = CStr(r("test"))} Into Group _
Where (Group.Count > 1) _
Select Dups
Dim dupRowList = (From r In dtPackageTest _
Join dupRow In tblDups _
On dupRow.testid Equals CInt(r("testid")) _
And dupRow.test Equals CStr(r("test")) _
Select r).ToList()
For Each dup In dupRowList
dtPackageTest.Rows.Remove(dup)
Next
Make following changes in your existing code,this will work as you expected :
(I guess this should be an old school logic but it works )
'Add order by - Order By Dups.testid
Dim tblDups = From r In dtPackageTest _
Group By Dups = New With {Key .testid = CInt(r("testid")), Key .test = CStr(r("test"))} Into Group _
Where (Group.Count > 1) Order By Dups.testid _
Select Dups
'Add order by - Order By r("testid")
Dim dupRowList = (From r In dtPackageTest _
Join dupRow In tblDups _
On dupRow.testid Equals CInt(r("testid")) _
And dupRow.test Equals CStr(r("test")) Order By r("testid") _
Select r).ToList()
Dim id As Integer = 0
For Each dup In dupRowList
'Checking for testid is already removed or not
If id <> dup("testid") Then
id = dup("testid")
dtPackageTest.Rows.Remove(dup)
End If
Next

How to transform an SQL statement with Group by and Order By into a LINQ statement in vb.net

I have the following code working correctly, but was requested to combine it into one LINQ statement:
Dim AddlOrders = From ords In ctxi.V_TKT_HIST_BVs.AsEnumerable() _
Select ords Where (ords.CUST_NO = cstno) And (ords.ORIG_STA_ID <> "SWWEB") _
Order By ords.ORIG_TKT_NO Descending, ords.TKT_DT Descending
Dim AddlOrds As New Collection(Of V_TKT_HIST_BV)
Dim o As New V_TKT_HIST_BV
If (cstno Is Nothing) OrElse (AddlOrders Is Nothing) OrElse (AddlOrders.Count = 0) Then
AddlOrdersLabel.Text = "You have 0 additional orders."
AddlOrdersGrid.Visible = False
Else
For Each ord In AddlOrders
If prevord = String.Empty Then
prevord = ord.ORIG_TKT_NO
totord = ord.TOT
o = ord
ElseIf prevord = ord.ORIG_TKT_NO Then
totord += ord.TOT
Else
o.TOT = totord
AddlOrds.Add(o)
prevord = ord.ORIG_TKT_NO
totord = ord.TOT
o = ord
End If
Next
If o IsNot Nothing Then
AddlOrds.Add(o)
End If
Dim Addord = From ords In AddlOrds Order By ords.TKT_DT Descending
AddlOrdersGrid.DataSource = Addord
I have tried the following statement, but Visual Studio changes "Into os" to "Into os()" and gives a message that Definition of method os is not accessible in this context:
Dim orders = From o1 In ctxi.V_TKT_HIST_BVs
Where o1.CUST_NO = cstno
Group o1 By o1.TKT_DT, o1.ORIG_TKT_NO, o1.TOT
Into os() Select ORIG_ORD_NO, total = os.Sum(TOT),
tdate = os.Last(Function(v) v.TKT_DAT)
An example of the SQL would be like:
SELECT TOP (200) CUST_NO, EMAIL_ADRS_1, SUM(TOT) AS Expr1, ORIG_TKT_NO,
MIN(DISTINCT TKT_DT) AS Expr2
FROM V_TKT_HIST_BV
GROUP BY CUST_NO, EMAIL_ADRS_1, ORIG_TKT_NO
HAVING (EMAIL_ADRS_1 LIKE 'name%')
ORDER BY Expr2
Does anyone have an idea why it would change os into a method?
This would be it in C#:
AddlOrderGrid.DataSource=ctxi.V_TKT_HIST_BVs
.Where(t=>t.CUST_NO==cstno)
.Where(t=>t.ORIG_STA_ID!="SWWEB")
.GroupBy(t=>t.ORIG_TKT_NO)
.Select(t=> new {
CUST_NO=cstno,
EMAIL_ADRS_1=t.FirstOrDefault().EMAIL_ADRS_1,
TOT=t.SUM(u=>u.TOT),
ORIG_TKT_NO=t.Key,
TKT_DT=t.Min(u=>u.TKT_DT)
})
.OrderByDescending(t=>t.TKT_DT);
Converted to VB.NET:
Dim Addord = ctxi.V_TKT_HIST_BVs _
.Where(Function(t) t.CUST_NO = cstno) _
.Where(Function(t) t.ORIG_STA_ID <> "SWWEB") _
.GroupBy(Function(t) t.ORIG_TKT_NO) _
.Select(Function(t) New With { _
Key .CUST_NO = cstno, _
Key .EMAIL_ADRS_1 = t.FirstOrDefault().EMAIL_ADRS_1, _
Key .TOT = t.SUM(Function(u) u.TOT), _
Key .ORIG_TKT_NO = t.Key, _
Key .TKT_DT = t.Min(Function(u) u.TKT_DT) _
}).OrderByDescending(Function(t) t.TKT_DT)
If (Addord.Any()) Then
AddlOrderGrid.DataSource=Addord
Else
AddlOrdersLabel.Text = "You have 0 additional orders."
AddlOrdersGrid.Visible = False
Endif

Linq (Visual Basic) - Comparing two anonymous types yields no results

I am trying to write a linq query with a composite key. Here is the full query:
Dim qeRelationships = From p In qualificationElements _
Join r In relationships On New With {.ElementCode = r.Parent, .Type = r.ParentType} _
Equals New With {.ElementCode = p.ElementCode, .Type = p.Type} _
Join c In qualificationElements On New With {.ElementCode = r.Child, .Type = r.ChildType} _
Equals New With {.ElementCode = c.ElementCode, .Type = c.Type} _
Select New QualificationElementRelationship _
With {.Parent = p, _
.Child = c, _
.Relationship = r.RelationshipType, _
.Scope = r.Scope}
This is yielding no results and I am not sure why.
I have boiled it down to two examples. The following works and returns records:
Dim qeRelationships = From p In qualificationElements _
Join r In relationships On r.Child Equals p.ElementCode _
Select New _
With {.Relationship = r.RelationshipType, _
.Scope = r.Scope}
This next snippet does not work and does not return records
Dim qeRelationships = From p In qualificationElements _
Join r In relationships On New With {.a = r.Child} Equals New With {.a = p.ElementCode} _
Select New _
With {.Relationship = r.RelationshipType, _
.Scope = r.Scope}
Why does the first query work and the second fail?
Here is a quick post and answer! It is because all the properties of your anonymous class need to be marked up with the "Key" directive.
Dim qeRelationships = From p In qualificationElements _
Join r In relationships On New With {Key .a = r.Child} Equals New With {Key .a = p.ElementCode} _
Select New _
With {.Relationship = r.RelationshipType, _
.Scope = r.Scope}
The full query
Dim qeRelationships = From p In qualificationElements _
Join r In relationships On New With {Key .ElementCode = r.Parent, Key .Type = r.ParentType} _
Equals New With {Key .ElementCode = p.ElementCode, Key .Type = p.Type} _
Join c In qualificationElements On New With {Key .ElementCode = r.Child, Key .Type = r.ChildType} _
Equals New With {Key .ElementCode = c.ElementCode, Key .Type = c.Type} _
Select New QualificationElementRelationship _
With {.Parent = p, _
.Child = c, _
.Relationship = r.RelationshipType, _
.Scope = r.Scope}

list.longcount query using joins (Linq/Lambda)

I have two lists of class objects (Shifts and Employees) with which I am trying to create a join. I then need a count of the resulting items that match the search criteria.
Below is the code I am using, but because I can't find a way to pass the result back as a specific 'type' it's defaulting to boolean and warning me that this will cause a problem:
' Count Shifts for selected hour where: started before or on this
"hour" AND ends after or during this "hour" and Department = filter
value
intShift = Me.Shifts.LongCount(From myshift In Me.Shifts Join
myEmp In Me.EmployeesList On myshift.EmployeeName Equals myEmp.Name
Where myshift.Description = "Shift" And myshift.DateStart.Hour <=
myHour.Hour And myshift.DateEnd.Hour >= myHour.Hour _
And myshift.DateStart.Date = myDay.Date And myEmp.Department =
strFilter _ Or myshift.Description = "Overtime" And
myshift.DateStart.Hour <= myHour.Hour And myshift.DateEnd.Hour
>= myHour.Hour _
And myshift.DateStart.Date = myDay.Date And myEmp.Department =
strFilter)
The search without a join to the employee list and without the matching employee search filters works perfectly but just unable to combine the two.
I have searched for both linq/lambda and inner join examples, but I can't seem to find one that combines these with the longcount function.
I've tried to put together a minimal scenario based on your snippet.
If you request Count or LongCount directly from the query then the result appears to be as expected.
Dim Shifts() = {
New With {.DateStart = #1/1/2014#,
.DateEnd = #1/2/2014#,
.Description = "Overtime",
.EmployeeName = "Darren"}
}
Dim EmployeesList() = {
New With {.Name = "Darren",
.Department = "SO"}
}
Dim strFilter = "SO"
Dim myHour = #1/1/2014#
Dim myDay = myHour
Dim query =
From myshift In Shifts Join myEmp In EmployeesList _
On myshift.EmployeeName Equals myEmp.Name _
Where myshift.Description = "Shift" _
And myshift.DateStart.Hour <= myHour.Hour _
And myshift.DateEnd.Hour >= myHour.Hour _
And myshift.DateStart.Date = myDay.Date _
And myEmp.Department = strFilter _
Or myshift.Description = "Overtime" _
And myshift.DateStart.Hour <= myHour.Hour _
And myshift.DateEnd.Hour >= myHour.Hour _
And myshift.DateStart.Date = myDay.Date _
And myEmp.Department = strFilter
Console.WriteLine(query.Count)
Console.WriteLine(query.LongCount)

Linq syntax in VB.NET

What I really want is to select these two tables in to an anon type like in Scott Gu's blog: here However, I would settle for this created type "ActiveLots" I am joining two tables together and want to be able to reference columns from each in my result set.
I don't seem to be getting the syntax correctly.
Dim pi = From p In dc.Inventories Join i In dc.InventoryItems On p.InventoryItemID _
Equals i.InventoryItemID Where p.LotNumber <> "" _
Select New ActiveLots LotNumber = p.LotNumber, Quantity = p.Quantity, Item = i.Item, Uom = i.UnitofMeasure, Description = i.Description
Have a look at Daniel Moth's blog entry. I suspect you want:
Dim pi = From p In dc.Inventories _
Join i In dc.InventoryItems
On p.InventoryItemID Equals i.InventoryItemID _
Where p.LotNumber <> "" _
Select New With { .LotNumber = p.LotNumber, .Quantity = p.Quantity, _
.Item = i.Item, .Uom = i.UnitofMeasure, _
.Description = i.Description }
That's using an anonymous type - to use a concrete type, you'd use New ActiveLots With { ... (where ActiveLots has to have a parameterless constructor).