Hi i'm trying to join tables together when loading my session variable Below is my code
Dim cmdstring As String = "SELECT * FROM Users.Location_Code = Location.Location_Code =
Medical_Equipment.Location_Code WHERE Staff_No = #StaffNo"
I am attempting a 3 table join this data will then be presented on a grid view. Is it possible for a join to be made here in this string?
Yes it is possible. But you need to have proper SQL JOIN syntax. Your current SQL query doesn't make sense. It should look about like this (I assume that Staff_No is a column in Users table) :
Dim cmdstring As String = _
"SELECT * FROM Users u " & _
"INNER JOIN Location l on l.Location_Code = u.Location_Code " & _
"INNER JOIN Medical_Equipment m on m.Location_Code = u.Location.Location_Code " & _
"WHERE u.Staff_No = #StaffNo"
My apologies up front for the long thread.
I am very flabbergasted as to why this code is not working correctly.
Please have a look.
On markup,
<asp:TemplateField HeaderText="Action">
<ItemTemplate>
<asp:Button ID="cancelBtn" style="width:105px;padding:5px;margin:5px;" runat="server" CommandName="delete" OnDataBinding="btnDelete_DataBinding" OnClientClick='return confirm("Are you sure you want to delete this entry?");' Text="Cancel Training" />
</ItemTemplate>
</asp:TemplateField>
Then I have a function called getDateDifference() As Boolean with code below:
Private Function getDateDifference() As Boolean
Dim username = Session("Username")
Dim myConnectionString As [String] = ConfigurationManager.ConnectionStrings("DBConnectionString").ConnectionString
Dim myConnection As New SqlConnection(myConnectionString)
myConnection.Open()
Dim cmd1 As New SqlCommand("select DateDiff(dd,GetDate(),d.trainingDates) as DaysCount " & _
"from tblTrainings t Inner Join tblCourses c on t.courseId = c.courseId " & _
"Inner Join tblLocations l on t.locationId = l.LocationId " & _
"Inner Join tblTrainingDates d on t.dateid=d.dateid " & _
"Inner Join tblCourseInstructor ic on c.courseId = ic.CourseId " & _
"Inner Join tblInstructors i on ic.instructorId = i.instructorId " & _
"Inner Join tblLogin lg on t.username = lg.username where lg.username = #username", myConnection)
cmd1.Parameters.AddWithValue("#username", username)
Dim dr1 As SqlDataReader = cmd1.ExecuteReader()
If dr1.Read() Then
Dim DaysCount As Integer = dr1("DaysCount")
Response.Write(DaysCount)
If DaysCount >= 2 Then
Return True
Else
Return False
End If
End If
Return False
End Function
The function is invoked below:
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim btn As Button = DirectCast(e.Row.FindControl("cancelBtn"), Button)
btn.Enabled = Not getDateDifference()
End If
End Sub
All we trying do to is compare trainingdates with current date.
If current date is within 24 hours (or 2 days) of training date, a user who has already signed up for a class, cannot cancel that class.
The user can cancel if current date is more than 2 days before training date.
To test, I have 2 trainings scheduled on my account.
One training date is 6/22/2013
The other training date is 6/29/2013.
When I run the query above, I get 1, and 8 days respectively.
This is correct because today's date is 6/21/2013 which is there is one day left before first training date of 6/22/2013 and 8 days left
before the second training date of 6/29/2013.
This means that on my app (please see screenshot), I expect to see one button disabled and the other enabled.
![enter image description here][1]
As you can see from screenshot, this is not happening. Both are either getting enabled or disabled no matter what the training date is.
When I try to debug DaysCount with response.write (DaysCount), it shows 11.
Not sure how this is happening. It has been at least 3 days since I have been struggling with this.
DB is sql server 2005. However production db is 2008.
Thanks in advance for your assistance.
I'm not sure what is happening here, but to try and debug it I would just return d.trainingDates from your database query instead of doing the DateDiff, and then do this to validate it:
If dr1.Read() Then
Dim trngDate As Date = dr1("trainingDates")
Response.Write(trngDate.ToString)
If (trngDate - DateTime.Now).TotalDays >= 2 Then
Return True
Else
Return False
End If
End If
EDIT
But - why not just compare the dates in the RowDataBound event.
There is no need to perform another query, the date your are comparing is in the row you are binding
Something like this (untested) code:
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim dateValue As Date = Date.Parse(Convert.ToString(DataBinder.Eval(e.Row.DataItem, "Dates")))
Dim btn As Button = DirectCast(e.Row.FindControl("cancelBtn"), Button)
btn.Enabled = (dateValue - DateTime.Now).TotalDays >= 2
End If
End Sub
I know you accepted #Matt Wilko's answer, but just to answer the specific problem you're facing:-
The problem is that your query returns all tblTraining records for the user. There is no condition in the where clause to determine which tblTraining record is the current active one.
Response.Write(DaysCount) did not produce 11, but rather produced 1 and 1, which is the difference between 6/22/2013 and 6/21/2013. You had 2 rows, so each digit must have been for a different row, and both rows seems to be getting the same date difference.
You will probably need to declare Private Function getDateDifference(courseId as Integer) As Boolean or something similar, so that you can pass the courseId to the function and use it in your SQL statement to identify the specific training program that you want. Probably your SQL statement will look something like
Dim cmd1 As New SqlCommand(_
"select DateDiff(dd,GetDate(),d.trainingDates) as DaysCount " & _
"from tblTrainings t Inner Join tblCourses c on t.courseId = c.courseId " & _
"Inner Join tblLocations l on t.locationId = l.LocationId " & _
"Inner Join tblTrainingDates d on t.dateid=d.dateid " & _
"Inner Join tblCourseInstructor ic on c.courseId = ic.CourseId " & _
"Inner Join tblInstructors i on ic.instructorId = i.instructorId " & _
"Inner Join tblLogin lg on t.username = lg.username " & _
"where lg.username = #username and " & _
"t.courseId = #courseId", myConnection)
cmd1.Parameters.AddWithValue("#courseId", courseId)
As to where you can get your courseId, you can probably use the approach #Matt Wilko used. But then again, his method would have avoided this whole issue altogether.
OK so here is what's pulling my hair out ! I have a page which reads records from a table in one DB, manipulates the data slightly, then writes it to another DB.
In the Do While Not EOF loop, I have a number of If Then Else statements to manipulate the data.
If I run the code in full, most of the If Then Else do not work, if I run the page with just each one in there, they work fine.
I have spent 8 hrs+ working on this and am still baffled
Dim rsndb, fieldstr1, fieldstr2, fieldstr3, fieldstr4, fieldstr5, fieldstr6, fieldstr7, fieldstr8, fieldstr9, fieldstr10, fieldstr11, fieldstr12, fieldstr13, fieldstr14, fieldstr15
recordstr = 0
'##### Empty temp table #####
Set Connection = Server.CreateObject("ADODB.Connection")
Connection.Open "DSN=website"
cSql = "DELETE FROM newtandltest"
Connection.Execute (cSql)
Connection.Close
Set Connection = Nothing
' Select Records From House Database
Set adoCon = Server.CreateObject("ADODB.Connection")
adoCon.Open "DSN=newdatabase;UID=Intranet;Pwd=password;"
Set rsndb = Server.CreateObject("ADODB.Recordset")
strSQL="Select top 500 VendorTransaction.VendorNo As propvendor, Resort.ResortCode As rid, Resort.ResortName As resname, Locations.LocationName As proploc, Country.CountryCode As propcountry, Season.SeasonDesc As propsea, Property.SeasonDesc As propextrasea, Property.Size As psize, Property.Occupancy As occ, FloatingPoints.FloatingPointsName As TAOLF, Property.StartWeek As propsw, Property.EndWeek As propew, Property.Weeks As propweeks, Property.Points As proppoints, Property.WebPricePW As webprice, Property.Priority As priority, Property.OpenToOffer As offers, Property.PoAOffer As poa, Property.RentalPW As rentalpw, Property.WebDate As webdate"
strSQL = strSQL & " From Property Inner Join Resort On Property.ResortId = Resort.Id Inner Join Country On Resort.CountryId = Country.Id Inner Join Locations On Resort.LocationId = Locations.Id Inner Join FloatingPoints On Property.FloatPointId = FloatingPoints.Id Inner Join PropertyStatus On Property.StatusId = PropertyStatus.Id Inner Join PropertyType On Property.TypeId = PropertyType.Id Inner Join Season On Property.SeasonId = Season.Id Inner Join VendorTransaction On VendorTransaction.propertyId = Property.Id Where (Property.WebDate >= DateAdd(day, -187, GetDate()) And Property.StatusId = 4 and year(Property.WebDate) <> 9999)"
rsndb.Open strSQL, adoCon
Set adoCon1 = Server.CreateObject("ADODB.Connection")
adoCon1.Open "DSN=website"
Do While not rsndb.EOF
'------------------------------------------------------------------------------------------------------------------
fieldstr1 = rsndb("webdate")
'------------------------------------------------------------------------------------------------------------------
fieldstr2 = rsndb("propvendor")
'------------------------------------------------------------------------------------------------------------------
fieldstr3 = rsndb("propcountry")
If rsndb("proploc") = "FLOR" Then
fieldstr3 = rsndb("proploc")
End If
If rsndb("proploc") = "MADE" Then
fieldstr3 = rsndb("proploc")
End If
If rsndb("propcountry") = "ESC" Then
fieldstr3 = rsndb("propcountry") & left(rsndb("proploc"),1)
End If
'------------------------------------------------------------------------------------------------------------------
resnamestr = replace(rsndb("resname"),chr(13)," ")
resnamestr = replace(rsndb("resname"),chr(34),"")
resnamestr = replace(rsndb("resname"),"'","")
fieldstr4 = resnamestr
'------------------------------------------------------------------------------------------------------------------
fieldstr5 = rsndb("propsea")
If len(rsndb("propextrasea")) > 3 Then
fieldstr5 = rsndb("propextrasea")
End If
If rsndb("propcountry") = "POIN" Then
fieldstr5 = ""
End If
'------------------------------------------------------------------------------------------------------------------
fieldstr6 = ""
'------------------------------------------------------------------------------------------------------------------
fieldstr7 = rsndb("propweeks")
If rsndb("propcountry") = "POIN" Then
fieldstr7 = rsndb("proppoints")
End If
'------------------------------------------------------------------------------------------------------------------
If rsndb("propsw") = rsndb("propew") Then
fieldstr8 = rsndb("propsw")
End If
If rsndb("propcountry") = "POIN" Then
fieldstr8 = "POINTS"
fieldstr9 = "n/a"
End If
If rsndb("propsw") < rsndb("propew") Then
fieldstr8 = rsndb("propsw") & "/" & rsndb("propew")
End If
If rsndb("TAOLF") = "F" Then
fieldstr8 = "FLOATING"
End If
'------------------------------------------------------------------------------------------------------------------
tempsize = rsndb("psize")
Select Case tempsize
Case 1
fieldstr9 = "Studio" & " - " & rsndb("occ")
Case 2
fieldstr9 = "1 Bedroom" & " - " & rsndb("occ")
Case 3
fieldstr9 = "2 Bedroom" & " - " & rsndb("occ")
Case 4
fieldstr9 = "3 Bedroom" & " - " & rsndb("occ")
Case 5
fieldstr9 = "4 Bedroom" & " - " & rsndb("occ")
End Select
'------------------------------------------------------------------------------------------------------------------
fieldstr10 = rsndb("rid")
'------------------------------------------------------------------------------------------------------------------
fieldstr11 = rsndb("rid")
'------------------------------------------------------------------------------------------------------------------
fieldstr12 = ""
'------------------------------------------------------------------------------------------------------------------
fieldstr13 = "N"
'------------------------------------------------------------------------------------------------------------------
fieldstr14 = rsndb("webprice")
If rsndb("offers") = 1 Then
fieldstr14 = "Offers"
End If
If rsndb("poa") = 1 Then
fieldstr14 = "POA"
End If
'------------------------------------------------------------------------------------------------------------------
fieldstr15 = rsndb("rentalpw")
lCount = lCount + 1
Set Connection1 = Server.CreateObject("ADODB.Connection")
Connection1.Open "DSN=website"
cSql = "INSERT INTO newtandltest(datefield, field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, price, bargainprice)"
cSql = cSql & "VALUES('"&fieldstr1&"','"&fieldstr2&"','"&fieldstr3&"','"&fieldstr4&"','"&fieldstr5&"','"&fieldstr6&"','"&fieldstr7&"','"&fieldstr8&"','"&fieldstr9&"','"&fieldstr10&"','"&fieldstr11&"','"&fieldstr12&"','"&fieldstr13&"','"&fieldstr14&"','"&fieldstr15&"');"
Connection1.Execute (cSql)
Connection1.Close
Set Connection1 = Nothing
rsndb.MoveNext
Loop
rsndb.Close
adoCon.Close
Set rsndb = Nothing
Set adoCon = Nothing
I am with Shadow Wizard. Tidy up your code, only use rsndb once for every key. And use a dictionary to store your fields with reasonable names. As it is now, it is not maintainable: How should someone know what fieldStr12 stands for?
There is one real bug I spotted: You do three times a replace on the original string, so effectively only the last replace will be visible.
Suggestion how to tidy your code:
Do While not rsndb.EOF
Set fld = createObject("Scripting.Dictionary")
fld.Add "webdate", rsndb("webdate")
fld.Add "propvendor", rsndb("propvendor")
fld.Add "propcountry", rsndb("propcountry")
' etc...
Select Case fld("proploc")
Case "FLOR" fld("propcountry") = fld("proploc")
Case "MADE" fld("propcountry") = fld("proploc")
End case
If fld("propcountry") = "ESC" Then
fld("propcountry") = fld("propcountry") & left(fld("proploc"),1)
End If
' This part is not correct, it is only replacing the ' by an empty string
'resnamestr = replace(rsndb("resname"),chr(13)," ")
'resnamestr = replace(rsndb("resname"),chr(34),"")
'resnamestr = replace(rsndb("resname"),"'","")
'fieldstr4 = resnamestr
fld("resname") = replace(fld("resname"), chr(13), " ")
fld("resname") = replace(fld("resname"), chr(34), "")
fld("resname") = replace(fld("resname"), "'", "")
' etc...
Set Connection1 = Server.CreateObject("ADODB.Connection")
Connection1.Open "DSN=website"
cSql = "INSERT INTO newtandltest(datefield, field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, price, bargainprice)"
' the Items property of a dictionary is an array in the same order that you add them to the dictionary
' You could do the same with the Keys property.
cSql = cSql & "VALUES('" & join(fld.Items, "','") & "');"
Connection1.Execute (cSql)
Connection1.Close
Set Connection1 = Nothing
rsndb.MoveNext
Loop
Something u can improve in your code.
1) You have open connection before while loop so you do not need to open it again in While loop it should be remove
Set Connection1 = Server.CreateObject("ADODB.Connection")
Connection1.Open "DSN=website
While loop ...
WEND
Connection1.Close
Set Connection1 = Nothing
2) check Null and blank before replacing with some value.
for e.g
if(fld("resname") <> "" AND NOT ISNULL(fld("resname")))
replace(fld("resname"), chr(13), " ")
end if
- Note track loop with default value like response.write ("hello") and check in which row loop is breaking and by which cause
The only thing that I can see that might cause this is reading the same field more than once; with certain types of fields (e.g. Memo field of Access) it might become blank after the first read.
To fix such problem you need to read each field once, and store it into local variable:
Do While not rsndb.EOF
curPropLoc = rsndb("proploc")
curPropCountry = rsndb("propcountry")
'...
fieldstr3 = curPropCountry
If curPropLoc = "FLOR" Then
fieldstr3 = curPropLoc
End If
If curPropLoc = "MADE" Then
fieldstr3 = curPropLoc
End If
'...keep using curPropLoc instead of rsndb("proploc") throughout the loop...
'...keep using curPropCountry instead of rsndb("propcountry") throughout the loop...
'......
rsndb.MoveNext
Loop
I have a page that displays reports on a grid. The grid uses an Object data source which is bound to a class that returns data. The class itself uses standard SQL query to return a count of records and binds to a dataview. The issue we are having is that it takes about 10 minutes sometimes to load and I know there has to be a better way but cannot for the life of me, figure out what. Hoping to get some insights from anyone on how to optimize this for performance. The data class is shown below: any feedback would be appreciated. There are about 650 attorneys returned by the attorney view which is bound to 2 tables: attorneys and locations table. The view on which the counts are performed on is bound to 2 tables also: current cases and previous cases tables and that returns about 125,000 cases total. Caching is out of the question because the end user will be able to supply any start and end dates to generate the report.
Dim PendingStringBuilder As String = "((dbo.cases.attorney_id = dbo.attorneys.att_id) AND (dbo.cases.date_assigned <= #StartDate) AND (dbo.cases.closing_date >= #StartDate OR dbo.cases.closing_date IS NULL)) OR ((dbo.casepreviousattorneys.attorney_id =
dbo.attorneys.att_id) AND (dbo.casepreviousattorneys.previous_assignment_date <= #StartDate) AND (dbo.casepreviousattorneys.unassignment_date >= #StartDate OR dbo.casepreviousattorneys.unassignment_date IS NULL))"
Dim AssignedStringBuilder As String = "((dbo.cases.attorney_id = dbo.attorneys.att_id) AND (dbo.cases.date_assigned >= #StartDate) AND (dbo.cases.date_assigned <= #EndDate)) OR ((dbo.casepreviousattorneys.attorney_id = dbo.attorneys.att_id) AND (dbo.casepreviousattorneys.previous_assignment_date
>= #StartDate) AND (dbo.casepreviousattorneys.previous_assignment_date <= #EndDate))"
Dim CountTable As String = " dbo.cases WITH (NOLOCK) INNER JOIN dbo.tlkpcasetype ON dbo.cases.case_type_id = dbo.tlkpcasetype.case_type_id FULL OUTER JOIN dbo.casepreviousattorneys ON dbo.cases.case_no = dbo.casepreviousattorneys.case_no"
Dim dt As New DataTable("ReportTable")
Dim dr As DataRow
dt.Columns.Add("CasesPending", Type.[GetType]("System.Int32"))
dt.Columns.Add("CasesAssigned", Type.[GetType]("System.Int32"))
dt.Columns.Add("ProbationViolation", Type.[GetType]("System.Int32"))
dt.Columns.Add("BailOnly", Type.[GetType]("System.Int32"))
dt.Columns.Add("TotalCases", Type.[GetType]("System.Int32"))
dt.Columns.Add("AttorneyID", Type.[GetType]("System.Int32"))
dt.Columns.Add("AttorneyName", Type.[GetType]("System.String"))
dt.Columns.Add("AttorneyFirstName", Type.[GetType]("System.String"))
dt.Columns.Add("AttorneyLastName", Type.[GetType]("System.String"))
dt.Columns.Add("UnitID", Type.[GetType]("System.Int32"))
dt.Columns.Add("UnitName", Type.[GetType]("System.String"))
dt.Columns.Add("UnitType", Type.[GetType]("System.String"))
dt.Columns.Add("OfficeID", Type.[GetType]("System.Int32"))
dt.Columns.Add("Office", Type.[GetType]("System.String"))
If cn.State = ConnectionState.Closed Then cn.Open()
Dim cmd As SqlCommand
Dim rdr As SqlDataReader
strSQL = "SELECT DISTINCT dbo.attorneys.user_id, dbo.attorneys.att_id AS AttorneyID, dbo.attorneys.first_name +' '+ dbo.attorneys.last_name AS AttorneyName, dbo.attorneys.unit_id AS UnitID, dbo.tlkpunit.unit AS UnitName, dbo.tlkpunit.unit_type AS UnitType,
dbo.tlkpunit.office_id AS OfficeID, dbo.tlkpoffice.office AS Office, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprCasesPending FROM " & CountTable & " WHERE (" & PendingStringBuilder & ")) As CasesPending, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprCasesAssigned FROM " & CountTable & " WHERE (dbo.tlkpcasetype.case_type <> 'Probation Violation') AND (dbo.tlkpcasetype.case_type <> 'Bail Only') AND (" & AssignedStringBuilder & ")) As CasesAssigned,
"
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprProbationViolation FROM " & CountTable & " WHERE (dbo.tlkpcasetype.case_type = 'Probation Violation') AND (" & AssignedStringBuilder & ")) As ProbationViolation, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprBailOnly FROM " & CountTable & " WHERE (dbo.tlkpcasetype.case_type = 'Bail Only') AND (" & AssignedStringBuilder & ")) As BailOnly, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprTotalCases FROM " & CountTable & " WHERE (" & AssignedStringBuilder & ")) As TotalCases "
strSQL += " FROM dbo.attorneys WITH (NOLOCK) LEFT OUTER JOIN dbo.tlkpunit ON dbo.attorneys.unit_id = dbo.tlkpunit.unit_id LEFT OUTER JOIN dbo.tlkpdivision ON dbo.tlkpunit.division_id = dbo.tlkpdivision.division_id LEFT OUTER JOIN dbo.tlkpoffice ON dbo.tlkpunit.office_id
= dbo.tlkpoffice.office_id WHERE (dbo.tlkpunit.unit <> 'test-unit') "
cmd = New SqlCommand(strSQL, cn)
cmd.Parameters.AddWithValue("#StartDate", DateAStart)
cmd.Parameters.AddWithValue("#EndDate", DateAEnd)
rdr = cmd.ExecuteReader()
While rdr.Read
If rdr("CasesPending").ToString = 0 And rdr("CasesAssigned") = 0 And rdr("ProbationViolation").ToString = 0 And rdr("BailOnly") = 0 Then
'Do not add record
Else
dr = dt.NewRow()
dr("CasesPending") = CInt(rdr("CasesPending"))
dr("CasesAssigned") = CInt(rdr("CasesAssigned"))
dr("ProbationViolation") = CInt(rdr("ProbationViolation"))
dr("BailOnly") = CInt(rdr("BailOnly"))
dr("TotalCases") = CInt(rdr("TotalCases"))
dr("AttorneyID") = rdr("AttorneyID")
dr("AttorneyName") = rdr("AttorneyName")
dr("UnitID") = rdr("UnitID")
dr("UnitName") = rdr("UnitName")
dr("UnitType") = rdr("UnitType")
dr("OfficeID") = rdr("OfficeID")
dr("Office") = rdr("Office")
dt.Rows.Add(dr)
End If
End While
rdr.Close()
cmd.Dispose()
If cn.State = ConnectionState.Open Then cn.Close()
Dim dv As New DataView(dt)
dv.Sort = "AttorneyName ASC"
Return dv
Read up on "sql execution plans" and you may want to review your table indexes. It is likely that these things will yield the greatest results. See this SQL Server Optimization MSDN article for more information.
I also notice in your VB code you are not parameterizing your SQL string. You should consider doing this after the above for additional performance benefit.
For more information on using SQL parameters see:
http://www.codinghorror.com/blog/2005/04/give-me-parameterized-sql-or-give-me-death.html
http://technet.microsoft.com/en-us/library/ms186219.aspx
Try using a stored procedure. This will have the code compiled in the Sql Server already and the execution plan stored ahead of time. John
I have the following query:
Dim queryStudent = (From p In dbContext.Residents _
Where p.people_code_id = people_id _
Where p.year = year _
Where p.semester = semester _
Join b In dbContext.Buildings On p.building Equals b.id _
Join r In dbContext.Rooms On p.room Equals r.id
Select p, b, r)
I then attempt to pull the building and room for that individual like so:
room = queryStudent.FirstOrDefault.r.id
building = queryStudent.FirstOrDefault.b.id
But I receive an Object reference not set to an instance of an object error.
I tried doing something like
If IsNothing(queryStudent.FirstOrDefault.r.id) Then
room = ""
Else
room = queryStudent.FirstOrDefault.r.id
End If
But that still generates the same error.
Check if r is nothing instead of the id of r.
If IsNothing(queryStudent.FirstOrDefault.r) Then
room = ""
Else
room = queryStudent.FirstOrDefault.r.id
End If
I suspect queryStudent.FirstOrDefault is null. If you try to access a property of a null object, you get that exception. Try this approach:
If IsNothing(queryStudent.FirstOrDefault) Then
room = ""
Else If IsNothing(queryStudent.First.r) Then
room = ""
Else
room = queryStudent.FirstOrDefault.r.id
End If
In each case, you are checking that the object you are about to access is not null.