Cannot assign LINQ query to variable - vb.net

I want to declare a variable to hold the query result from LINQ to SQL like to the following:
Dim query As IQueryable(Of Student)
If isNoUserName Then
query = From st In db.Students _
Order By st.AssignedId Ascending _
Where (st.studentId = studentId _
Select st
Else
'' error here
query = From st In db.Students _
Order By st.firstName Ascending _
Join user In db.MSUsers On user.UserId Equals st.UserId _
Where st.studentId = studentId _
Select st.firstName, st.lastName, user.userName
End If
Return query
Error : conversions from 'System.Linq.IQueryable(Of )' to 'System.Linq.IQueryable(Of Student)'.
How do I declare variable "query" to hold both data from "Student" and "User" tables?
Thank you.

query is declared as being IQueryable<Student>, but it you look at the second query, you aren't actually returning students - you are returning a compiler-generated type composed of firstName, lastName and userName. Try changing the second query to end with:
Select st;
Edit:
Re needing data other than st, then you might try a trick to give query a type; I'll use C# for my illustration, as my VB is read-only:
var query = Enumerable.Repeat(new {firstName="",lastName="",userName=""}, 0);
...
if(isNoUserName) {
query = ...
select new {st.firstName, st.lastName, userName = ""};
} else {
query = ...
select new {st.firstName, st.lastName, user.userName };
}

Related

Using LINQ to Entity - How can I join/concatenate columns from another table

I am having some issues with trying to figure out the correct way, or syntax, to join/concatenate a series of "name" columns from a separate table into a query.
Currently I am testing in LINQpad using two queries; the first returns all the master data that I use for other background work, and the second is a user-friendly version that I bind to a DGV. The issue comes in when I try to join the Physicians names like I do for a separate combobox.
This is what I have thus far - while it does return the Physician's name, it will NOT return the name if the TITLE field is NULL on the Physicians table.
Dim query1 = (From demog In data_Demogs
From MedHist In data_Demog_MedHists.where(Function(a) demog.ID_Demog = a.ID_Demog).defaultifempty
From BGLAssay In data_Demog_BGLs.where(Function(a) demog.ID_Demog = a.ID_Demog).defaultifempty
Select
demog.ID_Demog,
demog.Last_Name,
demog.First_Name,
demog.ID_Demog_AKA,
demog.DOB,
demog.Gender,
demog.ST_Complete,
demog.LT_Complete,
demog.LT_Due_Date,
demog.ID_Physician,
demog.ID_Reason_For_Call,
demog.Intl_Patient,
demog.Mayo_Patient,
MedHist.ID_Disease_Group,
MedHist.ID_Disease_Type,
BGLAssay.ID_BGL_Assay)
Dim query2 = (From items In query1
From demogAKA In data_Demogs.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).defaultifempty
From DType In tbl_Disease_Types.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).defaultifempty
From DGroup In tbl_Disease_Groups.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).defaultifempty
From RFC In tbl_Reason_For_Calls.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).defaultifempty
From Phys In tbl_Physicians.Where(Function(a) items.ID_Physician = a.ID_Physician).defaultifempty
From Title In tbl_Titles.Where(Function(a) Phys.ID_Title = a.ID_Title).defaultifempty
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKA_Name = demogAKA.Last_Name + ", " + demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
Phys_Name = Phys.Last_Name + ", " + Phys.First_Name + ", " + Title.Title
).distinct
console.writeline(Query2)
This is the currently query I for a combobox that DOES bring back all names, joining those names even if a field is NULL.
Dim Phys = (From e In tbl_Physicians
Group Join f In tbl_Titles On e.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select e.ID_Physician,
e.Last_Name,
e.First_Name,
e.Middle_Initial,
m.Title
).ToArray().Select(Function(item) New With {
.ID = item.ID_Physician,
.Phys_Name = (String.Join(", ",
String.Join(",",
New String() {item.Last_Name, item.First_Name, item.Title}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries)))
})
Console.writeline(Phys)
When I try to add a third query to return just the Physician's name, and join that to the final query, I get the following error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
'Query 1 removed to save space
Dim PhysNames = (From e In tbl_Physicians
Group Join f In tbl_Titles On e.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select e.ID_Physician,
e.Last_Name,
e.First_Name,
e.Middle_Initial,
m.Title
).ToArray().Select(Function(item) New With {
.ID = item.ID_Physician,
.Phys_Name = (String.Join(", ",
String.Join(",",
New String() {item.Last_Name, item.First_Name, item.Title}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries)))
})
Dim query2 = (From items In query1
From demogAKA In data_Demogs.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).defaultifempty
From DType In tbl_Disease_Types.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).defaultifempty
From DGroup In tbl_Disease_Groups.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).defaultifempty
From RFC In tbl_Reason_For_Calls.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).defaultifempty
From Phys In PhysNames.Where(Function(a) items.ID_Physician = a.ID).defaultifempty
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKA_Name = demogAKA.Last_Name + ", " + demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
Phys.Phys_Name
).distinct
console.writeline(Query2)
When I try to join my working query into the final query, I get the following error:
Invalid cast from 'System.String' to 'VB$AnonymousDelegate_0`2[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934...
'Query1 removed to save space
Dim query2 = (From items In query1
From demogAKA In data_Demogs.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).defaultifempty
From DType In tbl_Disease_Types.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).defaultifempty
From DGroup In tbl_Disease_Groups.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).defaultifempty
From RFC In tbl_Reason_For_Calls.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).defaultifempty
From Phys In tbl_Physicians
Where items.ID_Physician = Phys.ID_Physician
Group Join f In tbl_Titles On Phys.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKA_Name = demogAKA.Last_Name + ", " + demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
PhysName = Function(a) String.Join(", ",
String.Join(",",
New String() {Phys.Last_Name, Phys.First_Name, m.Title}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries))
).distinct
console.writeline(Query2)
After a long time playing around in LINQpad, and then finally re-reading JM's answer to a former question I had, I realized what I was doing wrong.
As per his post:
The problem is that, while LINQ in general has no issue with that code, LINQ to Entities does. LINQ syntax is the same for every provider but the implementation under the hood differs and, in the case of LINQ to Entities, your LINQ code has to translated to SQL and, in this case, there's no mapping from String.Join to SQL. That code would work fine with LINQ to Objects so one solution is to push that operation out of the original query and into a LINQ to Objects query. That would mean selecting the raw data with your LINQ to Entities query, calling ToList or ToArray on the result to materialise the query, then performing another query on that result. That second query will be LINQ to Objects rather than LINQ to Entities and so String.Join will not be an issue.
So... Once I realized I needed to push out the String.Join, I ended up with the following code:
Dim DispList = (From items In MastList
From demogAKA In dbACL.data_Demog.Where(Function(a) items.ID_Demog = a.ID_Demog_AKA).DefaultIfEmpty
From DType In dbACL.tbl_Disease_Type.Where(Function(a) items.ID_Disease_Type = a.ID_Disease_Type).DefaultIfEmpty
From DGroup In dbACL.tbl_Disease_Group.Where(Function(a) items.ID_Disease_Group = a.ID_Disease_Group).DefaultIfEmpty
From RFC In dbACL.tbl_Reason_For_Call.Where(Function(a) items.ID_Reason_For_Call = a.ID_Reason_For_Call).DefaultIfEmpty
From e In dbACL.tbl_Physician.Where(Function(a) items.ID_Physician = a.ID_Physician).DefaultIfEmpty
Group Join f In dbACL.tbl_Title On e.ID_Title Equals f.ID_Title
Into Matched = Group
From m In Matched.DefaultIfEmpty()
Select
items.ID_Demog,
items.Last_Name,
items.First_Name,
AKALname = demogAKA.Last_Name,
AKAFname = demogAKA.First_Name,
items.DOB,
items.Gender,
items.ST_Complete,
items.LT_Complete,
items.LT_Due_Date,
DType.Disease_Type_Abr,
DGroup.Disease_Group_Name,
RFC.Reason_For_Call,
items.ID_Physician,
PLName = e.Last_Name,
PFname = e.First_Name,
PMI = e.Middle_Initial,
PTitle = m.Title
).Distinct.ToList().Select(Function(a) New With {
a.ID_Demog,
a.Last_Name,
a.First_Name,
.AKA_Name = (String.Join(", ",
String.Join(",",
New String() {a.AKALname, a.AKAFname}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries))),
a.DOB,
a.Gender,
a.ST_Complete,
a.LT_Complete,
a.LT_Due_Date,
a.Disease_Type_Abr,
a.Disease_Group_Name,
a.Reason_For_Call,
a.ID_Physician,
.PName = (String.Join(", ",
String.Join(",",
New String() {a.PLName, a.PFname, a.PTitle}).Split(
New Char() {","}, System.StringSplitOptions.RemoveEmptyEntries)))
}).ToList()

Linq IEnumerable to entity cast error

Please refer to my following code. An exception error occurs at the return value.
Unable to cast object of type 'System.Data.Objects.ObjectQuery1[VB$AnonymousType_23[System.String,System.String,System.String]]' to type 'System.Collections.Generic.List`1[MyEntities.stk_cust]'.
Public Function GetCustomerProdListToGrid() As List(Of stk_cust)
Dim result = From s In Db.stk_cust
Group Join d In Db.s_armaster On d.dbcode Equals s.dbcode Into stk_ar = Group
From d In stk_ar.DefaultIfEmpty()
Order By s.stk_code, s.dbcode Ascending
Select s.stk_code, s.dbcode, d.name
Return result
End Function
I've tried the following method at select section but error turns out the same
Select New With {.stk_code = s.stk_code,
.dbcode = s.dbcode,
.name = d.name
}
Any help is highly appreciated.
If you want to return a List(Of stk_cust) you need to create instances of stk_cust instead of using an anonymous type. Presuming that those are the properties:
....
Select New stk_cust() With {
.stk_code = s.stk_code,
.dbcode = s.dbcode,
.name = d.name
}
Return result.ToList()
Maybe you could also select the object directly without needing to create a new one:
Dim result = From s In Db.stk_cust
Group Join d In Db.s_armaster On d.dbcode Equals s.dbcode Into stk_ar = Group
From d In stk_ar.DefaultIfEmpty()
Order By s.stk_code, s.dbcode Ascending
Select s
Return result.ToList()

"sum" of string separates with "," in linq to entities

I need a query of Linq to Entities with the result is a unic string separates with ",".
I try with Cont = String.Join(", ", op.OperacionesContenedores.Select(Function(jj) jj.Id.ToString).ToArray())
Example:
(From op In dContext.Operaciones
Join opTr In dContext.OperacionesTransito On opTr.idOperacion Equals op.id
Group Join opTrContenedor In dContext.OperacionesContenedores On opTr.idOperacion Equals opTrContenedor.IdOperacion Into grpOpTrContenedor = Group
From opTrContenedor In grpOpTrContenedor.DefaultIfEmpty()
Select New With {.idOperacion = op.id,
.Expediente = op.ReferenciaEmpresaResponsable,
.ReferenciaCliente = op.ReferenciaEmpresaCliente,
.Cont = String.Join(", ", op.OperacionesContenedores.Select(Function(jj) jj.Id.ToString).ToArray())
}).Distinct().AsQueryable
This should return "Expediente", "referenciaCliente", "con1, cont2, cont3", but in query execution produces a error:
LINQ to Entities does not recognize the method 'System.String Join(System.String, System.String[])' method, and this method cannot be translated into a store expression.

Nested Linq Queries Saga

So I am trying to write something like this:
SELECT s.CompanyID,
s.ShareDate,
s.OutstandingShares,
s.ControlBlock
FROM (
SELECT MAX(ShareDate) AS Sharedate,
CompanyID
FROM ShareInfo
WHERE (ShareDate <= #filter_date)
GROUP BY CompanyID
) AS si
INNER JOIN
tblShareInfo AS s ON s.ShareDate = si.Sharedate AND s.CompanyID = si.CompanyID
Essentially this is trying to return the most recent Share Information, we keep a running history. Now I am trying to write something similar to this in LINQ.
Here was my closest attempt:
From a _
In db_context.ShareInfos _
Where a.ShareDate <= filter_date _
Group a By a.CompanyID Into Group _
Select CompanyID, MostRecentShareDate = Group.Max(Function(a) a.ShareDate) _
Join b In db_context.ShareInfos On b.CompanyID Equals a.CompanyID _
Select b.CompanyID, b.ShareDate, b.OS, b.CB()
Unfortunately this does not compile. Obviously I'm not understanding the LINQ syntax somehow. Can anyone steer me in the right direction?
Thanks.
with your last select statement you should use
select new {
CompanyID = b.CompanyID,
ShareDate = b.ShareDate,
OS = b.OS,
CB = b.CB
};
that's a start...
Okay so looks like this needs to be done using two statements:
Dim MostRecentShareDates = _
From s2 In query_collection.DBContext.ShareInfos _
Where s2.ShareDate <= filter_date _
Group s2 By s2.CompanyID Into Group _
Select New With { _
.CompanyID = CompanyID, _
.MostRecentShareDate = Group.Max(Function(s3) s3.ShareDate) _
}
Return From s In query_collection.DBContext.ShareInfos _
Join s1 In MostRecentShareDates On s.CompanyID Equals s1.CompanyID And s.ShareDate Equals s1.MostRecentShareDate _
Select New With { _
.CompanyID = s.CompanyID, _
.ShareDate = s.ShareDate, _
.OS = s.OS, _
.CB = s.CB _
}
I tried using the 'Let' keyword to embed the first statement into the second, but that would not compile either. Now the nice thing about this is the Linq has delayed execution, so until you traverse the collection returned by the second statement, no SQL gets generated. Linq is then smart enough to combine the two code fragments into one SQL statement, essentially exactly the same statement as I wrote in my original SQL above.

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).