Entity Framework query with "not in" - vb.net

I have a simple (well easy, not simple) query of "not in" on related tables.
SELECT CompetencyID, CompetencyName FROM Competency
WHERE (Deleted = 0) AND (CompanyID = 1) AND (CompetencyID NOT IN(SELECT CompetencyID
FROM CompetencyGroups WHERE (Deleted = 0) AND (CompanyID = 1) AND (GroupID = 1))) AND
(ParentID = 0) ORDER BY CompetencyName
In SQL I get the list that I need with remaining items not in the group. Now I want to bind this to a DataGrid using EF5.
I cannot get the query syntax properly (Using VB.net) to list the ID and the Name of the Competency...
Converted the provided c# answer to VB:
Dim excludeList = context.CompetencyGroups.Where(Function(x) x.Deleted = False And x.GroupID = GroupID).Select(Function(x) x.CompetencyID).ToArray
Dim results = context.Competencies.Where(Function(c) Not excludeList.Contains(c.CompetencyID) And c.Deleted = False And c.CompanyID = 1 And c.ParentID = 0).OrderBy(Function(c) c.CompetencyName)
GridView2.DataSource = results
GridView2.DataBind()
Hope this helps someone in the future. Took me about 4 hours to search, ask and convert...

Something like
var excludeList = context.CompetencyGroups.Where(x => x....).Select(x => x.CompetencyID).ToArray();
var results = context.Competency.Where(x => !excludeList.Contains(x.CompetencyID));
Update: Somebody else edited this and then someone rejected it, but the edit was a good one (to select the value)

If you need the Cast to make an array of Integers.
Dim excludeList = context.CompetencyGroups.Cast(Of CompentencyGroup).Select(Function(x) x.CompetencyID).ToArray()
Dim results = context.Competency.Where(Function(x) Not excludeList.Contains(x.CompetencyID))

Related

What is the Purpose of the IsNull in this query?

I have a desktop application that I am converting to web and I am having trouble understanding the purpose of the IsNull parts of the query. The query is for Ms SQL and I know it has a IsNull function but this is not it. So I'm confused as to it's purpose. Below is my query:
UPDATE tb_category
SET
Email = #Email,
CandidateID = #CandidateID,
Code = #Code,
TestDate = #TestDate,
Description = #Description,
PointsEarned = #PointsEarned,
PointsAvailable = #PointsAvailable,
Average25th = #Average25th,
Average75th = #Average75th,
ImportedDate = #ImportedDate,
CreationDate = #CreationDate,
TestNum = #TestNum,
CategoryNum = #CategoryNum
WHERE ((Email = #Original_Email)
AND (CandidateID = #Original_CandidateID)
AND (Code = #Original_Code)
AND (TestDate = #Original_TestDate)
AND ((#IsNull_Description = 1 AND Description IS NULL) OR (Description = #Original_Description))
AND (PointsEarned = #Original_PointsEarned)
AND ((#IsNull_PointsAvailable = 1 AND PointsAvailable IS NULL) OR (PointsAvailable =
#Original_PointsAvailable))
AND ((#IsNull_Average25th = 1 AND Average25th IS NULL) OR (Average25th = #Original_Average25th))
AND ((#IsNull_Average75th = 1 AND Average75th IS NULL) OR (Average75th = #Original_Average75th))
AND ((#IsNull_ImportedDate = 1 AND ImportedDate IS NULL) OR (ImportedDate = #Original_ImportedDate))
AND ((#IsNull_CreationDate = 1 AND CreationDate IS NULL) OR (CreationDate = #Original_CreationDate))
AND (TestNum = #Original_TestNum)
AND (CategoryNum = #Original_CategoryNum));
I tried simplifying the update statement by removing the IsNull sections but that did not work.
In SQL null is not equal (=) to anything—not even to another null, so in your query in case if both values are null (old and new one) you need to take that into account and check values with IS NULL.
I'm seeing this pattern repeated several times in the WHERE clause:
#IsNull_Description = 1 AND Description IS NULL
It means that a variable, #IsNull_SomeColumnName, which is presumably set earlier in the code, has a value of 1, and the column that the variable relates to is currently NULL.
The function IsNull(Param1, Param2) is used to substitute the value of the second parameter for the value of the first parameter if the first parameter IS NULL, and the function returns the value of Param2.
In SQL Server, and quite a few other RDBMSs, the IS NULL syntax is used to check if a value is currently NULL. Here, Description IS NULL will return TRUE if, well, Description is null, and FALSE if it is not.

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

vb6 to vb.net for OracleInProcServer.OraDynaset

I am converting a project which is coded in old vb6 way. I am replacing the instances of OracleInProcServer.OraDynaset to Datatable for getting the data from database. But a form is generated in a dynamic way has the below code. i don't know how be there a alternate code for there in vb.net. Is there any way I can replace the below code without using dsAnswer As OracleInProcServer.OraDynaset. I don't know what is ! here also and how it is working.
Dim dsAnswer As OracleInProcServer.OraDynaset
Select Case dsAnswer!Shape.Value
Case 0 To 5
iShapes = iShapes + 1
'Load(f!shpCtrl(iShapes))
frmDynaForm.shpCtrl.Load(iShapes)
frmDynaForm.shpCtrl(iShapes).FillColor = System.Drawing.Color.FromArgb(DecodeColorDesc(Format$(dsAnswer!Color.Value)))
'frmDynaForm.shpCtrl(iShapes).Shape = dsAnswer!Shape.Value
frmDynaForm.shpCtrl(iShapes).Top = dsAnswer!Top.Value
frmDynaForm.shpCtrl(iShapes).Left = dsAnswer!Left.Value
frmDynaForm.shpCtrl(iShapes).Height = dsAnswer!Height.Value
frmDynaForm.shpCtrl(iShapes).Width = dsAnswer!Width.Value
frmDynaForm.shpCtrl(iShapes).BorderWidth = dsAnswer!BorderWidth.Value
frmDynaForm.shpCtrl(iShapes).Visible = True
Case -1
iLines = iLines + 1
'Load(f!lineCtrl(iLines))
frmDynaForm.lineCtrl.Load(iShapes)
frmDynaForm.lineCtrl(iLines).BorderColor = System.Drawing.Color.FromArgb(DecodeColorDesc(Format$(dsAnswer!Color.Value)))
frmDynaForm.lineCtrl(iLines).Y1 = dsAnswer!Top.Value
frmDynaForm.lineCtrl(iLines).X1 = dsAnswer!Left.Value
frmDynaForm.lineCtrl(iLines).Y2 = dsAnswer!Height.Value
frmDynaForm.lineCtrl(iLines).X2 = dsAnswer!Width.Value
frmDynaForm.lineCtrl(iLines).BorderWidth = dsAnswer!BorderWidth.Value
frmDynaForm.lineCtrl(iLines).Visible = True
End Select

Where clause on dynamic column name in LINQ query?

I've created a dropdown with some column names in a table in my db. When a user selects a column name i want to add a where clause to the query to use this filter.
What i'm trying to do is:
Dim objQuery = (From wc In _dbBellen.dealer_telefonies Order By wc.Bedrijfsnaam Select wc)
'if dropdown has value...
objQuery = objQuery.Where(Function(wc) wc.DynamicColumnName < txtFilterValue1.Text)
The wc.DynamicColumnName has to be replaced by for example wc.Price.
--
The code what i'm tried now after some replies is:
Dim objQuery = (From wc In _dbBellen.dealer_telefonies Order By wc.Bedrijfsnaam Select wc)
If ddlFilterColumn1.SelectedValue <> "" And ddlFilterOperator1.SelectedValue <> "" And txtFilterValue1.Text <> "" Then
Select Case ddlFilterOperator1.SelectedValue
Case "..%"
objQuery = objQuery.Where(Function(wc) wc.WHMCSClient_id Like txtFilterValue1.Text & "%")
Case "%.."
objQuery = objQuery.Where(Function(wc) wc.WHMCSClient_id Like "%" & txtFilterValue1.Text)
Case Else '< > = <>
'objQuery = objQuery.Where(Function(wc) wc.WHMCSClient_id < txtFilterValue1.Text)
'objQuery = objQuery.Where(Function(wc) "wc." + ddlFilterColumn1.SelectedValue.ToString + " < " + txtFilterValue1.Text)
objQuery = objQuery.Where(Function(wc) "wc.WHMCSClient_id < 500")
End Select
End If
Response.Write(objQuery.ToString())
But i am getting the following error (original error is in dutch but it said as follow):
The conversion from string wc.WHMCSClient_id < 500 to type Boolean is invalid.
This is quite an old article, but I think it's still viable
Scott Gu posted about the Dynamic LINQ library a while back which essentially allows you to use strings to query collections in a "LINQ"-type format., i.e. something like this:
Dim objQuery = (From wc In _dbBellen.dealer_telefonies Order By wc.Bedrijfsnaam Select wc)
// if dropdown has value...
Dim result = objQuery.Where("MyColumnName < " + txtFilterValue1.Text);
Here's a link to the full article: Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)

Linq query returning value from another class

Just a quick question about LINQ, I want to use a value from the returned dataset to lookup a value and return this. The line I am struggling with is .ViewingNotes = New Viewing(pt.ProspectId).GetViewings().Columns(7).ToString(). Is this possible?
With BusinessLayerObjectManager.Context
Return (From p As [Property] In .PropertySet
Join pt As Prospect In .Prospects On pt.Property.propertyID Equals p.propertyID
Where (p.Development.DevelopmentID = devId)
Select New DevelopmentList With {
.Apartment = p.propertyApartment + " " + p.Development.Name,
.PropertyId = p.propertyID,
.Client = pt.Client.clientFirstname + " " + pt.Client.clientLastname,
.ClientId = pt.Client.ClientID,
.ProspectiveDate = pt.prospectiveDate,
.ProspectiveStatus = pt.prospectiveStatus,
.Agent = pt.Client.userID,
.ViewingNotes = New Viewing(pt.ProspectId).GetViewings().Columns(7).ToString(),
.PropertyStatus = ""
}).ToList()
End With
Thanks in advance.
I suspect not, when the compiler tries to convert the 'Viewing(pt.ProspectId).GetViewings().Columns(7).ToString()' bit to SQL it will get very confused. You would need to do it in 2 stages.
Do the first Linq-to-entity select first returning just pt.ProspectId, with the .ToList() intact. Then use the results to do some more linq, linq-to-linq if you like, where you can do the lookup using a lambda.