Sql table check - asp.net

I have a table with the following fields ID IDuser IDpc FROM TO.
obviously a PC cannot be used during the same time period by more than one user. how do i place a constraint on entries so that incorrect entries are prevented?
I use sql Server 2016 (management studio) with asp.net

ok, as noted, I though the part about multiple users using the same PC had to do with multi-user databases!
I now see that you are booking a PC to be used, and you don't want booking collisions.
Ok, there is a VERY neat condition to test/check for a booking collision.
It looks like this:
A collision occurs when:
RequestStartDate <= EndDate
and
RequestEndDate >= StartDate
And if the values include date + time, then the above still works just fine.
The above condition will find ANY kind of overlap (so a date/time in the middle) or any parts that overlap.
As I suggested in comments? You could get/have the data base not allow you to add that row (you would have to use a table trigger).
However, then what?
What this REALLY suggests? You don't write out the record and expect a database failue. Worse yet, you really want to give the user some nice feed back.
So, your booking page would ask for the room, and then the start/end time (with date). You use the above condition, and if record(s) are returned, then you tell the user they can't book the room. However, if no matches occur, then you add that row to the database.
This kind of problem actually seems quite difficult, but it turns out with the above simple condition, is is remarkable simple.
Lets do this simple example as a asp.net webforms.
So, drop in a list box, two text boxes (start/end) and a book button.
So, the markup looks like this:
<div style="margin-left:40px">
<h2>Book a work station</h2>
<div style="float:left">
<h3>Select a work station</h3>
<asp:ListBox ID="lstCompter" runat="server"
DataTextField="Computer" DataValueField="ID" Height="151px" Width="294px"></asp:ListBox>
</div>
<div style="float:left;margin-left:20px">
<div style="float:left">
<h3>Start Time</h3>
<asp:TextBox ID="txtStart" runat="server" TextMode="DateTimeLocal"></asp:TextBox>
</div>
<div style="float:left;margin-left:20px">
<h3>End Time</h3>
<asp:TextBox ID="txtEnd" runat="server" TextMode="DateTimeLocal"></asp:TextBox>
</div>
<div style="clear:both;float:left;margin-top:40px">
<asp:Button ID="cmdBook" runat="server" Text="Book Room" />
</div>
<div style="clear:both;float:left">
<br />
<asp:Label ID="lblMsg" runat="server" Text=""></asp:Label>
</div>
</div>
</div>
I tossed in a few divs to lay this out.
Ok, now the code to load up the listbox was this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData()
End If
End Sub
Sub LoadData()
Using cmdSQL As New SqlCommand("SELECT ID, Computer from Computers ORDER BY Computer",
New SqlConnection(My.Settings.TEST4))
cmdSQL.Connection.Open()
lstCompter.DataSource = cmdSQL.ExecuteReader
lstCompter.DataBind()
End Using
End Sub
And now we get this:
Note that if you drop in that textbox and in the property sheet choose DateTimeLocal as the format, then without any extra code, you get that way cool date = time picker for free.
Now, lets write the code to check for if we can book.
The user selects a room, and then the start/end times (that could be for 1 hour, or one 1 week - it don't matter.
So, now our book button code looks like this:
Protected Sub cmdBook_Click(sender As Object, e As EventArgs) Handles cmdBook.Click
Dim strSQL As String
strSQL = "SELECT * FROM Bookings WHERE IDPc = #IDpc " &
"AND #RequestStart <= [TO] " &
"AND #RequestEnd >= [From] "
Using cmdSQL As New SqlCommand(strSQL, New SqlConnection(My.Settings.TEST4))
cmdSQL.Parameters.Add("IDpc", SqlDbType.Int).Value = lstCompter.SelectedItem.Value
cmdSQL.Parameters.Add("#RequestStart", SqlDbType.DateTime).Value = txtStart.Text
cmdSQL.Parameters.Add("#RequestEnd", SqlDbType.DateTime).Value = txtEnd.Text
cmdSQL.Connection.Open()
Dim rstBooking As New DataTable
rstBooking.Load(cmdSQL.ExecuteReader)
If rstBooking.Rows.Count > 0 Then
' booking not allowed - show message
lblMsg.Text = "Computer station already booked - try differnt date/time"
Else
' add this booking
Dim da As New SqlDataAdapter(cmdSQL)
Dim daupdate As New SqlCommandBuilder(da)
Dim OneRow As DataRow = rstBooking.Rows.Add
OneRow("IDpc") = lstCompter.SelectedValue
OneRow("IDUser") = LogOnID
OneRow("From") = txtStart.Text
OneRow("To") = txtEnd.Text
da.Update(rstBooking)
lblMsg.Text = "Room booked!"
End If
End Using
End Sub
Note how simple this becomes. In about the SAME time it took me to write this post? I in fact have a real working booking page. It would need more love an care then a quick dirty example like above, but all in all, it is remarkable that the above works.
our Computers (table) to book for the list box was this:
And then the booking table of course is this:
And that is quite much it. You can see we query the database, and if we find a match (collision), then we NEVER even try to add the row, and we give a user that message.
But, if now rows are found, then we add the row to the database.
So, it will look like this:
It is times like this that one realizes how amazing simple this was in asp.net.
Enjoy!
FYI: both "to" and "from" are SQL words - you have to use [To] and [From] (brackets around) those words, since SQL server will get confused - those column names are what we call reserved words - and "FROM" is part of regular sql syntax, so just remember to use those [] around the sql.

Related

Get child page data from master page selectedItems

I have location DropdownList in my master page. I have set control in my child page which takes properties from master page. Now I am running a query
SELECT * FROM table where city like '"+city.text+"'
here city.text gets value from master page selected cities. But my problem is it's not actually showing records as per city.text has values in it. It shows any random records.
My Code
Master Page
<asp:DropDownList ID="locationSelector" runat="server" AutoPostBack="true">
<asp:ListItem Selected>Pune</asp:ListItem>
<asp:ListItem>Delhi</asp:ListItem>
<asp:ListItem>Chennai</asp:ListItem>
<asp:ListItem>Bangalore</asp:ListItem>
<asp:ListItem>Mumbai</asp:ListItem>
</asp:DropDownList>
Child page VB Code
Dim location As DropDownList = Page.Master.FindControl("locationSelector")
city.Text = location.SelectedItem.ToString
If Not IsPostBack Then
Try
query = "SELECT * FROM hospitals where city like '" + city.Text + "'"
Dim cmd As New MySqlCommand(query, con)
cmd.CommandTimeout = 120
Dim da As New MySqlDataAdapter(cmd)
Dim table As New DataTable
da.Fill(table)
ViewState("Data") = table
hospitals.DataSource = table
hospitals.DataBind()
Catch ex As Exception
Response.Write(ex)
End Try
End If
UPDATE
Protected Sub hospitals_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
Dim location As DropDownList = Page.Master.FindControl("locationSelector")
city.Text = location.SelectedItem.ToString
End Sub
Sometimes it also throws TimeOut error. But most of the time It gets results but not as per selected items. What will be any other solution for this?
A couple of tips:
1) Timeout errors can happen for a number of reasons, including lots of other traffic to the site, connection pools all used up etc. I would, for a small list of cities, maybe keep that in a cache after the first call, so that you do not need to load the city list from database every time. Depending on your country, if you only have a few thousand cities, then just put it in an in-memory list.
2) You are using a "SELECT *" which is usually not really cool to other developers, nor to your code if the table contains more than just a city name. IF you write Select CityName from Table, then you will effectively have reduced the amount of data going from your database to your program, and it is clear to the other developers exactly what you're pulling from that table.
3) If you have an ID for the city, it will likely perform even better as string matcing is REALLY slow compared to matching a couple of ID's. I've seen 20% speed improvements by replacing strings with constants, you wouldn't believe how slow strings are in code these days.
4) Last, and I think you may already have done this, make sure that you INDEX every field that you do a WHERE filter on. If you search for Hospitals, then make sure that the Hospitals.City field is indexed to avoid row lookups.
I hope (any) of this helps you :)
As per my understanding you need to change below
to fetch the selected TEXT value use location.SelectedItem.Text instead of location.SelectedItem.ToString()
city.Text = location.SelectedItem.Text // change here
before binding the dropdown control check the no. of rows
if(table.Rows.Count>0)
{
hospitals.DataSource = table;
hospitals.DataBind();
}
I would suggest to use prerender event within page. In prerender event try to access your master page control and get value.

Select Query on Access Database in Visual Studio

heres my code :
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
ltRooms.Text = CInt(Session("numOfRooms"))
'Calculate total cost
Dim intPrice As Integer
Dim intTotal As Integer
intPrice = AccessDataSource1.SelectCommand = "SELECT [Price] FROM [Rooms] WHERE ([RoomType] = 'RoomType')"
intTotal = intPrice * intRooms
ltPrice.Text = intTotal.ToString
End Sub
and my datasource
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="Hostel.accdb"
SelectCommand="SELECT * FROM [Bookings]"></asp:AccessDataSource>
I'm trying to store the value from the select query and then use it to work out the total price and then store it in a literal. So far I am only getting 0. No compile errors.
Does anyone one know why this isn't working?
I am consolidating the various comments into an answer for clarity and to stop the page complaining about extended discussion. This is all off the top of my head so there might be some errors in the code. It should be enough to pinpoint the problem though.
Firstly, now that I look at it again today, I think your code is just setting the SelectCommand property of the data source and not actually querying the database. I think you need to use the DataSource.Select method.
Your code might end up looking something like this:
AccessDataSource1.SelectCommand = "SELECT [Price] FROM [Rooms] WHERE ([RoomType] = '" & RoomType & "')"
Dim intPrices As List(Of Integer) = AccessDataSource1.Select(DataSourceSelectArguments.Empty)
' Now do stuff with your price data.
If the above doesn't help then I would check the value of intPrice returned by the Select call. You should also check that RoomType is set correctly.
If the wrong data is coming back from the database then you should be able to fix your SQL query to retrieve the correct data. If you need further assistance with this then please post the SQL query and the table structure.
If the correct data is coming back then check where intRooms is defined. If it is zero then your total will be calculated as zero regardless of the value of intPrice.

Adding duplicate rows of data to my access database

Hey there Im having difficulties adding a single row of data to my database when I submit my form it insert two rows of data to my mdb database any suggestions samples or help will work ill really appreciate it Thanks
Protected Sub Button3_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim conCoaxis As OleDbConnection
Dim strInsert As String
Dim cmdInsert As OleDbCommand
conCoaxis = New OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source=C:\site\App_Data\sabersolutions.mdb")
strInsert = "INSERT INTO register (Name, Email, Newsletter) Values (?, ?, ?)"
cmdInsert = New OleDbCommand(strInsert, conCoaxis)
cmdInsert.Parameters.Add("#Name", OleDbType.VarWChar, 255).Value = txtName.Text
cmdInsert.Parameters.Add("#Email", OleDbType.VarWChar, 255).Value = txtEmail.Text
cmdInsert.Parameters.Add("#Newsletter", OleDbType.Boolean, 1).Value = ckNews.Checked
Try
conCoaxis.Open()
cmdInsert.ExecuteNonQuery()
conCoaxis.Close()
Response.Write("Updated Successfully!<p> </p><p> </p><p> </p>")
Catch
conCoaxis.Close()
End Try
Your code looks fine. It looks to me more like you have the sub-routine Button3_Click assigned as the handler more than once. For example in the aspx page you have something like
<asp:Button runat="server" ID="Button3" Text="Submit" OnClick="Button3_Click" />
See the OnClick attribute? that wires the click event to call Button3_Click
Then somewhere else, possibly in Page_Load in the .vb code-behind, you also have:
AddHandler Button3.Click, AddressOf Me.Button3_Click
So ONE click event will end up calling the same function twice. Get rid of the AddHandler code you don't need to manually wire-up click handlers, it's done for you.
If that's not your problem you may of course be clicking your button twice, this is a well known issue with HTML forms. You can Google many solutions. My preferred solution is to always do a 'SELECT' first to check if the record already exists, or wrap your insert command in a 'IF NOT EXISTS' (I think this works for MS Access, I know it dows for MS Sql Server)
strInsert = "IF NOT EXISTS (SELECT 1 FROM register WHERE Name = #Name AND Email = #Email AND Newsletter = #Newsletter) BEGIN INSERT INTO register (Name, Email, Newsletter) Values ( #Name, #Email, #Newsletter) END"
Another option is:
strInsert = "INSERT INTO register (Name, Email, Newsletter) SELECT TOP 1 #Name, #Email, #Newsletter FROM register WHERE NOT EXISTS (SELECT 1 FROM register WHERE Name = #Name AND Email = #Email AND Newsletter = #Newsletter)"
This latter statement only works if 'register' has at least one record in it, MS Access Jet database requires a table name in the statement, see here for more info. Seriously though, drop Access and use a proper database like SQL Server, then you can use the first statement directly or via a stored procedure a much more professional solution.

Populating dropboxes with SQL data

I have a few more questions regarding my latest project. Ive felt like I have made some pretty good strides over the last couple days, but I am still struggling on a few of the core concepts of the SQL libraries, namely reading from specific columns and deleting entire rows.
Over the last week I was able to build a webform, save excel files to the server, open those files and export data into specific SQL tables, and bind the data to specific data grids depending on what the user chooses through a dropdown.
What I would like to accomplish is: Dynamic population of another dropdown depending on what the user chooses from the first drop down. More specifically, I have 4 tables, in the first column of each table I have serial numbers, if the user chooses Table2 in the first drop down, I would like the second dropdown to display all the serial numbers from column1 of Table2. Then if the user choose a specific serial number from the second drown down it populates a datagrid with columns 1-5 of that related row.
The second part is to create a delete button that the user can push after the information is displayed in the datagrid, that deletes the entire row of the serial number entry from that table.
This is what I have managed to Frankenstein together from other examples:
Protected Sub DropDownList1_SelectedIndexChanged(sender As Object, e As System.EventArgs)
DropDownList2.Enabled = True 'its remains disabled until the user selects something from the first box
Using con As New SqlClient.SqlConnection
con.ConnectionString = "Data Source=.\SQLEXPRESS;AttachDbFilename=" & AppPath & "App_Data\DeviceDatabase.MDF;Integrated Security=True;User Instance=True;"
Using cmd As New SqlClient.SqlCommand
cmd.Connection = con
End Using
Dim cmdSQL As New SqlCommand()
cmdSQL.CommandType = Data.CommandType.Text
cmdSQL.CommandText = "SELECT Fieldname1 FROM " & """" & DropDownList1.SelectedItem.ToString & """" 'Im pretty sure this isnt right, and the reason I use """"" is because some of the items in the dropdown have spaced words.
Dim adptSQL As New SqlClient.SqlDataAdapter(cmdSQL)
Dim myDataSet As New DataSet()
adptSQL.Fill(myDataSet)
With myDataSet.Tables(DropDownList1.SelectedIndex) 'I think this is right
For rowNumber As Integer = 0 To .Rows.Count - 1
With .Rows(rowNumber)
DropDownList2.Items.Add(col1.rowNumber) 'This is obviously not working
End With
Next
End With
End Using
End Sub
Then, Im not quite sure how to populate the data table with the row that was selected, though currently I am able to do the entire table with using:
Private Sub GenTables(ByVal DropList As Object)
If DropList.SelectedIndex = 0 Then
GridView1.DataSourceID = Nothing
ElseIf DropList.SelectedIndex = 1 Then
GridView1.DataSourceID = "SqlDataSource1"
ElseIf DropList.SelectedIndex = 2 Then
GridView1.DataSourceID = "SqlDataSource2"
ElseIf DropList.SelectedIndex = 3 Then
GridView1.DataSourceID = "SqlDataSource3"
ElseIf DropList.SelectedIndex = 4 Then
GridView1.DataSourceID = "SqlDataSource4"
End If
GridView1.DataBind()
End Sub
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:DeviceDatabaseConnectionString1 %>"
ProviderName="<%$ ConnectionStrings:DeviceDatabaseConnectionString1.ProviderName %>"
SelectCommand="SELECT [Device:] AS column1, [SWversion:] AS column2, [Date:] AS column3, [Tester:] AS column4, [Wifi Preferred InCov:] AS column5 FROM [Galaxy Nexus]">
</asp:SqlDataSource>
'there are 3 more of these.
But I have these tables "hard coded" into the application, I can't obviously do this with every single table row. So how do I populate a datagrid without setting a SQLDataSource ahead of time in asp?
And lastly deleting the row that relates to the information displayed in the datagrid on the click of a button. If if can get a little help with the first part, Im sure I can figure out the second part.
So pretty much what I am asking is: how to populate a drop down with all the items from Coloumn1? and how to populate a datagrid from a specific row?
Any and all help is always greatly appreciated. Thanks Guys
Zach
EDIT
hmm I think I was making this a ton harder then it had to be, right now I am working with this:
Protected Sub BindDrop_Click(sender As Object, e As System.EventArgs)
DropDownList2.DataSourceID = "SqlDataSource5"
DropDownList2.DataBind()
End Sub
<asp:SqlDataSource ID="SqlDataSource5" runat="server"
ConnectionString="<%$ ConnectionStrings:DeviceDatabaseConnectionString1 %>"
ProviderName="<%$ ConnectionStrings:DeviceDatabaseConnectionString1.ProviderName %>"
SelectCommand="SELECT [Device:] AS column1 FROM [Galaxy Nexus]">
Its not quite right but its closer and in 1/10th the lines
alright guys i figured it out, I needed to use the ExecuteReader function (which crazily enough I couldnt find one article in auto population that uses this method). Hopefully in writing/answering this I make someone's life much easier.
Protected Sub DropDownList2_SelectedIndexChanged(sender As Object, e As System.EventArgs)
DropDownList3.Enabled = True
DropDownList3.Items.Clear()
Dim newsqlcommand As String = "Select [SWversion:] FROM " & """" & DropDownList2.SelectedItem.ToString & """"
Using con As New System.Data.SqlClient.SqlConnection(connexstring)
con.Open()
Using cmd As New SqlCommand(newsqlcommand, con)
Dim myReader As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
While myReader.Read()
DropDownList3.Items.Add(myReader.GetString(0))
End While
myReader.Close()
cmd.Dispose()
End Using
con.Close()
con.Dispose()
End Using
Dbind()
End Sub
This successfully reads all the items in the column "SWVersion" and adds them to the dropdown in dropdown3. Enjoy!

Open new window in asp.net VB

I'm a noob progammer that is working on something for our company. I'm working on a Quiz engine for training. I have some sample code that is about 90% built. I just need to tweak a few things. Here's what I'm working on.
THis is built in ASP.net with VB. I have a set of questions that I"m pulling from a database (using the built-in SQLDataSource binding). Currently what it does is pull the question, you select the answer, and click Next. It then pulls the next question in the list and so forth....till the end. The Database contains a column that indicates what the correct answer is. When you click next, it compairs your answer to the correct answer, stores it, then continues to the next question. At the end, it spits out your correct answers and incorrect answers.
However, this is what I want to do. When the user selects an answer and clicks next, it immediately opens up a small new window (not a pop-up, but a window on the same page) that immediately "grades" that question and in that window, displays whether it's correct..something like this:
If selected answer = correctAnswer then
"That is correct"
Else
"THat is not correct. The correct answer is B"
End if
The new window will only contain an "OK" button in the bottom corner. When the OK is pressed, it closes that new window and processes the rest of what the "next" button is programmed to do. Here is the button:
<asp:Button ID="buttonNext" runat="server" Text="Next" /> </td>
Here is the Questions.aspx.VB code to go along with that:
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles buttonNext.Click
' Save off previous answers
Dim dr As System.Data.DataRowView
dr = CType(questionDetails.DataItem, System.Data.DataRowView)
' Create Answer object to save values
Dim a As Answer = New Answer()
a.QuestionID = dr("QuestionOrder").ToString()
a.CorrectAnswer = dr("CorrectAnswer").ToString()
a.UserAnswer = answerDropDownList.SelectedValue.ToString()
Dim al As ArrayList
al = CType(Session("AnswerList"), ArrayList)
al.Add(a)
Session.Add("AnswerList", al)
If questionDetails.PageIndex = questionDetails.PageCount - 1 Then
' Go to evaluate answers
Response.Redirect("results.aspx")
Else
questionDetails.PageIndex += 1
End If
If questionDetails.PageIndex = questionDetails.PageCount - 1 Then
buttonNext.Text = "Finished"
End If
End Sub
If you are able to provide the code I need, that will be helpful. Thanks in advance for the help.
Tim
This should be fairly straight forward. As you have already retrieved the correct answer there is no need to do another call.
On your page you need to create a where you want the grading and OK button to live.
Something like this would suffice:
<div id="gradeWindow" runat="server" visible="false">
<asp:label id="gradeLabel" runat="server" text="" />
<asp:button id="gradeOK" runat="server" text="OK" onclick="gradeOK_Clicked" />
</div>
Then modify your function to look like this
Session.Add("AnswerList", al)
If String.Compare(a.UserAnswer, a.CorrectAnswer) = 0 then
gradeLabel.Text = "That is correct"
Else
gradeLabel.Text = "That is not correct. The correct answer is " + a.CorrectAnswer
EndIf
gradeWindow.Visible = true
End Sub
Protected Sub gradeOK_Clicked(ByVal sender As Object, ByVal e As System.EventArgs)
If questionDetails.PageIndex = questionDetails.PageCount - 1
Then
Response.Redirect("results.aspx")
Else
questionDetails.PageIndex += 1
End If
If questionDetails.PageIndex = questionDetails.PageCount - 1
Then
buttonNext.Text = "Finished"
End If
End Sub

Resources