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

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}

Related

Linq with multiple where clauses not pulling back data

I am using VB.NET and Linq; I have two separate conditions that have to be satisfied. When I run them individually they work fine however when I combine them into a single statement with multiple where statements then I get 0 records returned.
If I run the first where clause without the 2nd I get 70 records
If I run the 2nd where clause without the first i get 5 records
When I run with both where clauses I get 0 records returned
Here is the code.
submissionDetails = (From r In model.NIBRS_ReportStatusByORI
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And Not r.ReportType = "ZERO REPORT" _
And r.OccurrenceDate >= sCritera.BeginDate _
And r.OccurrenceDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And r.ReportType.Equals("ZERO REPORT") _
And r.YearMonthDate >= sCritera.BeginDate _
And r.YearMonthDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Select New ReportStatusDetails() With {
.ChangeDate = r.Insertdate,
.IncidentId = r.IncidentID,
.IncidentIdentifier = r.IncidentIdentifier,
.OriginatingORI = r.OriginatingORI,
.ReportType = r.ReportType,
.StatusID = r.StatusID,
.SubmittedBy = r.Username,
.ReportDate = r.YearMonthDate,
.ReportDateString = r.YearMonth,
.OccurrenceDate = r.OccurrenceDate
}).ToList()
Have you tried this:
submissionDetails = (From r In model.NIBRS_ReportStatusByORI
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And Not r.ReportType = "ZERO REPORT" _
And r.OccurrenceDate >= sCritera.BeginDate _
And r.OccurrenceDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Select New ReportStatusDetails() With {
.ChangeDate = r.Insertdate,
.IncidentId = r.IncidentID,
.IncidentIdentifier = r.IncidentIdentifier,
.OriginatingORI = r.OriginatingORI,
.ReportType = r.ReportType,
.StatusID = r.StatusID,
.SubmittedBy = r.Username,
.ReportDate = r.YearMonthDate,
.ReportDateString = r.YearMonth,
.OccurrenceDate = r.OccurrenceDate
}).Union(From r In model.NIBRS_ReportStatusByORI
Where (sCritera.ORI.Contains(r.OriginatingORI) _
And r.ReportType.Equals("ZERO REPORT") _
And r.YearMonthDate >= sCritera.BeginDate _
And r.YearMonthDate <= sCritera.EndDate _
And (r.ActionCode <> "D"))
Select New ReportStatusDetails() With {
.ChangeDate = r.Insertdate,
.IncidentId = r.IncidentID,
.IncidentIdentifier = r.IncidentIdentifier,
.OriginatingORI = r.OriginatingORI,
.ReportType = r.ReportType,
.StatusID = r.StatusID,
.SubmittedBy = r.Username,
.ReportDate = r.YearMonthDate,
.ReportDateString = r.YearMonth,
.OccurrenceDate = r.OccurrenceDate
}).ToList()

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

Left Outer Join Two Data Tables? [duplicate]

This question already has an answer here:
VB.Net LINQ - left outer join between two datatables - limit to one row
(1 answer)
Closed 8 years ago.
Is it possible to modify this LINQ method to perform a left outer join? Looking at LINQ queries, I'm in way over my head..
Private Function MergeTables(Of T)(ByVal dtForecast As DataTable,
ByVal dtDns As DataTable, _
ByVal fieldASelector As Func(Of DataRow, T), _
ByVal fieldBSelector As Func(Of DataRow, T), _
ByVal whereClauseA As Func(Of DataRow, Decimal), _
ByVal whereClauseB As Func(Of DataRow, Decimal))
Dim test = (From forecast In dtForecast.AsEnumerable() Join dns In dtDns.AsEnumerable() _
On fieldASelector(forecast) Equals fieldBSelector(dns) _
Where whereClauseA(forecast) <> 0 And whereClauseB(dns) <> 0 _
Select New With _
{ _
.ProductId = forecast.Field(Of String)("ProductID"), _
.Product = forecast.Field(Of String)("ProductName"), _
.Account = forecast.Field(Of String)("Account"), _
.BrandName = forecast.Field(Of String)("BrandName"), _
.CorrugateCost = forecast.Field(Of Decimal)("Corrugate_Cost"), _
.f_m1 = forecast.Field(Of Decimal)("f_m1"), _
.a_m1 = dns.Field(Of Decimal)("a_m1"), _
.f_m2 = forecast.Field(Of Decimal)("f_m2"), _
.a_m2 = dns.Field(Of Decimal)("a_m2"), _
.f_m3 = forecast.Field(Of Decimal)("f_m3"), _
.a_m3 = dns.Field(Of Decimal)("a_m3"), _
.f_m4 = forecast.Field(Of Decimal)("f_m4"), _
.a_m4 = dns.Field(Of Decimal)("a_m4"), _
.f_m5 = forecast.Field(Of Decimal)("f_m5"), _
.a_m5 = dns.Field(Of Decimal)("a_m5"), _
.f_m6 = forecast.Field(Of Decimal)("f_m6"), _
.a_m6 = dns.Field(Of Decimal)("a_m6"), _
.f_m7 = forecast.Field(Of Decimal)("f_m7"), _
.a_m7 = dns.Field(Of Decimal)("a_m7"), _
.f_m8 = forecast.Field(Of Decimal)("f_m8"), _
.a_m8 = dns.Field(Of Decimal)("a_m8"), _
.f_m9 = forecast.Field(Of Decimal)("f_m9"), _
.a_m9 = dns.Field(Of Decimal)("a_m9"), _
.f_m10 = forecast.Field(Of Decimal)("f_m10"), _
.a_m10 = dns.Field(Of Decimal)("a_m10"), _
.f_m11 = forecast.Field(Of Decimal)("f_m11"), _
.a_m11 = dns.Field(Of Decimal)("a_m11"), _
.f_m12 = forecast.Field(Of Decimal)("f_m12"), _
.a_m12 = dns.Field(Of Decimal)("a_m12"), _
.f_total = forecast.Field(Of Decimal)("f_total"), _
.a_total = dns.Field(Of Decimal)("a_total") _
}).ToList()
Return test
End Function
You can use Group Join + DefaultIfEmpty:
Dim joined = From forecast In dtForecast.AsEnumerable()
Group Join dns In dtDns.AsEnumerable()
On fieldASelector(forecast) Equals fieldBSelector(dns) Into Group
From x In Group.DefaultIfEmpty
Where whereClauseA(forecast) <> 0 And whereClauseB(dns) <> 0
Select New With
{
.ProductId = forecast.Field(Of String)(ProductID),
.a_m2 = If(x Is Nothing, New Nullable(Of Decimal), x.Field(Of Decimal)("a_m2"))
}
Use the following modification to your query to perfom Left Outer Join.
From forecast In dtForecast.AsEnumerable() Group Join dns In dtDns.AsEnumerable() _
On fieldASelector(forecast) Equals fieldBSelector(dns) Into JoinTable = Group _
From dns in JoinTable.DefaultIfEmpty()_
Where whereClauseA(forecast) <> 0 And whereClauseB(dns) <> 0 _
I recommend using this resource to help you with LINQ: 101 LINQ Samples. (Specifically for this question, go to "LINQ Query Samples" > "Join Operators" > Left Outer Join.)

LINQ CopyToDataTable -- Cannot cast DBNull.Value to type 'System.Decimal'. Please use a nullable type

I am parsing two Excel files that contain many fields, most importantly TOTAL_DOLLARS and TOTAL_UNITS fields, that often have values, but some of them are left blank, or null. I want to JOIN these two DataTables using LINQ where the UPC fields are equal. However, I have run into the following error:
Cannot cast DBNull.Value to type 'System.Decimal'. Please use a nullable type
This error occurs when I try to join the two tables because of the null fields.
My LINQ code is as follows:
Dim query = From c In dtDollars.AsEnumerable() _
Join r In dtUnits.AsEnumerable() _
On c.Field(Of String)("UPC") Equals r.Field(Of String)("UPC") _
Select _
New _
With {.UPC = r.Field(Of String)("UPC"), .WIC_NUMBER = c.Field(Of String)("WIC_NUMBER"), _
.WAG_ITEM_DESC = c.Field(Of String)("WAG_ITEM_DESC"), _
.WAG_BRAND = c.Field(Of String)("WAG_BRAND"), .UOM = c.Field(Of String)("UOM"), _
.GSK_PROMO_GRP = c.Field(Of String)("GSK_PROMO_GRP"), _
.TOTAL_DOLLARS = c.Field(Of Decimal)("TOTAL_DOLLARS"), _
.TOTAL_UNITS = r.Field(Of Integer)("TOTAL_UNITS"), _
.WKND_DATE = c.Field(Of DateTime)("WKND_DATE")}
Given that WKND_DATE can also be null, get the field as a Nullable(Of DateTime) (DateTime?) like so:
Dim query = From c In dtDollars.AsEnumerable() _
Join r In dtUnits.AsEnumerable() _
On c.Field(Of String)("UPC") Equals r.Field(Of String)("UPC") _
Select _
New _
With {.UPC = r.Field(Of String)("UPC"), .WIC_NUMBER = c.Field(Of String)("WIC_NUMBER"), _
.WAG_ITEM_DESC = c.Field(Of String)("WAG_ITEM_DESC"), _
.WAG_BRAND = c.Field(Of String)("WAG_BRAND"), .UOM = c.Field(Of String)("UOM"), _
.GSK_PROMO_GRP = c.Field(Of String)("GSK_PROMO_GRP"), _
.TOTAL_DOLLARS = c.Field(Of Decimal?)("TOTAL_DOLLARS"), _
.TOTAL_UNITS = r.Field(Of Integer?)("TOTAL_UNITS"), _
.WKND_DATE = c.Field(Of DateTime?)("WKND_DATE")}

PredicateBuilder + Join + 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.