I have `Total Number of Seats` and `Available Seats`. How do I manage the two? - asp.net

I struggled to come up with appropriate title for this thread.
Forgive me it isn't clearcut.
We have a table called Locations with following attributes:
locationID --Each location has 30 capacity seating per class
Capacity_Seating --this is total allowed seat per class per location.
When a user logs in, s/h is presented with a dropdownlist of locations to choose from. Whichever location the trainee chooses, is the location s/he is going to take the training at.
The Capacity seating for each location is 30.
As soon as the user logs in, s/he is taken to the Trainring page. The training displays general information about the classes, including the date and time of training, duration, the Capacity Seating and most importantly, available seats or Seats remaining.
If seats are still available, the user can click Register to register for that particular training.
Once this user is registered, the available seat changes.
For instance, if there were 15 seats prior to this trainee registering, then after registering, the available seating with now read 14 seats.
If a user chooses to cancel his or her seat after initially registering, the trainee can do so as long as it isn't within 24 hours of training date.
Here are my questions.
1, do I need to add another field called Available_Seats to the location table or to the Training table to show how many seats remain or can this be done using a query like:
Select (Capacity_Seating - each time trainee registers)?? Not sure how to handle this.
2, We would like to use register to substract a number from Capacity_Seating and Cancel to put back a number to Capacity_Seating.
Your thoughts and assistance are greatly appreciated.
<ItemTemplate>
<asp:LinkButton ID="Btncalc" runat="server" Text="Register" tooltip="Click to calculate" onclick="calc" />
</ItemTemplate>
</asp:TemplateField>
</ItemTemplate>
Sub calc(ByVal sender As Object, ByVal e As System.EventArgs)
Dim objConnection As SqlConnection
Dim username = Session.Item("Username").ToString
' Dim strSQL As String
objConnection = New SqlConnection(ConfigurationManager.ConnectionStrings("DBConnectionString").ConnectionString)
objConnection.Open()
strSQL = "update TrainingTable set employeeId='" & username
strSQL += "', AvailableSeats= AvailableSeats-1"
strSQL += " where location = '" & ddlLocation.SelectedValue.ToString & "'"
'Response.Write(strSQL)
'Response.End()
Dim cmdcommand As New SqlCommand(strSQL, objConnection)
cmdcommand.ExecuteNonQuery()
cmdcommand = Nothing
objConnection.Close()
objConnection = Nothing
End Sub
By the way, markup is on gridview.

For your first question how you would like to proceed mostly comes down to what you would like to do. Having another field for the available seats in a table or finding the remaining seats using a query are both viable options. The benefits or pitfalls of either are really negligible given the basic structure of your system. Seeing as you would use a specific query to find this piece of information constantly it would be better practice and sense to add this value in as a new field in the table. This will eliminate the need for a specific query and make this data more public to other systems and queries.
For your second question I'm not quite sure I follow it but I'll try to give you my best opinion. It seems you want to alter the total capacity field from each table based on registrations and cancellations which I would disagree with. The capacity value shouldn't be modified if the actually total capacity of location does not change. So rather than changing the total capacity through cancels or registrations I would change that new available seats field. This leaves no chance for confusion when viewing the capacity of the location and will easily allow you to find the available spaces for registration.

This is a simple module:
It gives you a choice of a particular course, with two venues and an option of reg or adv course at each venue (this doesn't affect the seating)
I have NOT included the SQL OR server side scripts, at this stage.. this algorithm should help.
You don't need to add another column to your table, just update the fields as the program is implemented, and you can delete a row, if it is cancelled. I haven't included code for that.. (it's too long!!! hahaha)
(NB this doesn't error check for datatype - it's a simple format to get an idea)
Module Module1
Sub main()
Dim Seat As Object
Dim Course As Object
Dim Person1 As Integer
Dim Venue1 As Integer
Dim Venue2 As Integer
Dim regular As Integer
Dim Advanced As Integer
Dim x As String
Do
Person1 = Person1 + 1
If Venue1 = 30 Then
Console.WriteLine("Venue1 is full")
End If
If Venue2 = 30 Then
Console.WriteLine("Venue2 is full")
End If
Console.WriteLine("enter 1 for Venue1, 2 for Venue2")
Seat = Console.ReadLine
If Seat = 1 Then
Venue1 = Venue1 + 1
Else
Venue2 = Venue2 + 1
End If
Console.WriteLine("Regular course = 1, Advanced course = 2")
Course = Console.ReadLine
If Course = 1 Then
regular = regular + 1
Else
Advanced = Advanced + 1
End If
Console.WriteLine("Press enter to continue, r for reports or x to quit")
x = Console.ReadLine
If x = "r" Then
Console.WriteLine("total Persons= " & Person1 & vbCrLf & "total Venue1= " & Venue1 & vbCrLf & "total Venue2=" & Venue2 & vbCrLf & "Course: regular " & regular & vbCrLf & "Advanced " & Advanced)
ElseIf x = "x" Then
Exit Do
Else
End If
Loop Until Person1 = 60
If Person1 = 60 Then
Console.WriteLine("Course is full.")
End If
End Sub
End Module
Please let me know if you need any more help or clarity.

Related

Sql table check

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.

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.

Looking for a custom filter than simulates the "Update Project" for status reporting

I am currently working with Project Server 2013, PWA and Project 2013 Pro. I am trying to create a dashboard, and require a planned %complete in a project that has no budget, or costs associated with it.
This means I have to create a custom filter that will mimic the Update Project button in the project status tab.
Has anyone else had to do this, or can you provide alternatives I can use?
I wrote something similar to do this in 2010 - I assume it will work in 2013, although can't test it.
Although you don't have any budget or costs, I'm assuming that you do have a baseline with hours against it. That being the case, the following code will output the Planned % Complete (i.e. the proportion of hours you should have burnt on a given task by the status date) to field text11
Option Explicit
Sub CalcBaselinePerctComplete()
Dim pj As Project
Dim t As Task
Dim TSV As TimeScaleValue
Dim TSVs As TimeScaleValues
Dim HrsValue As Double
Dim PerctValue As Integer
Set pj = ActiveProject
For Each t In pj.Tasks
Select Case pj.StatusDate
Case Is > t.BaselineFinish
'If the baseline end date is in the past, then the PerctValue must be 100%
'so no need to loop through the time scaled PerctValues
PerctValue = 100
Case Is < t.BaselineStart
'If the baseline start date is in the future, then the PerctValue must be 0%
'so no need to loop through the time scaled PerctValues
PerctValue = 0
Case Else
If t.BaselineWork = 0 Then
'if there is no baseline work, then the PerctValue must be 1005
'otherwise we've be dividing by zero
PerctValue = 100
Else
Set TSVs = t.TimeScaleData(t.Start, pj.StatusDate, pjTaskTimescaledBaselineWork, pjTimescaleDays)
HrsValue = 0
For Each TSV In TSVs
If TSV.Value <> "" Then
HrsValue = HrsValue + TSV.Value
End If
Next TSV
PerctValue = HrsValue / t.BaselineWork * 100
End If
End Select
SetValue:
t.Text11 = PerctValue & "%"
Next t
End Sub

Filter taking 2 seconds on small adbodb recordset

I have a small adodb recordset I am trying to filter. This one is 6 records for our test customer.
For some reason the filter is taking 2 seconds to complete, and I am doing this around 30 times on my asp page. Thus, making my page really slow to load. The other recordset filters on this page are running fast.
I have tried setting different CursorLocations and CursorTypes..
Can anyone help me determine why this filter is so slow?
rsAvgPrice.Filter = "CommodityID = 13 AND CropYear = '12'"
Probably the whole query is executed again and only then the filter is being applied.
I would have one single loop over all the items, store the required data in local variables then have my own filter. Best efficiency, much better control.
For example, if you want the data filtered by those two fields, I would use Dictionary like this:
Dim oCommodity_CropYear_Data, curKey
Dim curCommodityID, curCropYear, curData
Set oCommodity_CropYear_Data = Server.CreateObject("Scripting.Dictionary")
Do Until rsAvgPrice.EOF
curCommodityID = rsAvgPrice("CommodityID")
curCropYear = rsAvgPrice("CropYear")
curKey = curCommodityID & "_" & curCropYear
curData = "field1: " & rsAvgPrice("somefield") & ", field 2: " & rsAvgPrice("other_field") & "<br />"
oCommodity_CropYear_Data(curKey) = oCommodity_CropYear_Data(curKey) & curData
rsAvgPrice.MoveNext
Loop
rsAvgPrice.Close
Then to extract the data in a loop:
For x=1 To 30
For y=1 To 12
curKey = x & "_" y
If oCommodity_CropYear_Data.Exists(curKey) Then
Response.Write("Data for Commodity " & x & " and CropYear " & y & ":<br />" & oCommodity_CropYear_Data(curKey)
End If
Next
Next
This is the general idea, hope you can use it for your actual needs.
I have resolved this issue.
The issue was when I declare a record set the following way, the cursor type gets set as adOpenForwardOnly and the cursor location to adUseServer. These settings cannot be changed if you fill your recordset using command.Execute.
Set cmd = Server.CreateObject("ADODB.Command")
cmd.CommandType = adCmdText
cmd.CommandText = mySQL
cmd.CommandTimeout = 3000
cmd.ActiveConnection = cn
Set rs = Server.CreateObject("ADODB.Recordset")
Set rs = cmd.Execute
Set cmd = Nothing
The way I resolved this was manually declaring a permanent recordset with its fields. Then I filled a temporary recordset using the command.execute. I then manually populated my declared recordset with the temporary recordset record by record. This allowed me to set the cursorlocation to adUseClient.
Thus speeding up the filter by leaps and bounds.

Entity Framework: Create Change History

I have a EDM (phoneDB) that models a back-end MSSQL database. I've developed a ASP.NET (VB) application that allows one to edit the information in this database. When someone edits a record entry I'd like to record this action.
Right now, I'm doing the following:
For Each..Next that checks whether entry is an object that has had its entitystate modified.
And If Not..End If that ensures we aren't dealing with a relationship entity or a null entity.
Now this is where it gets fuzzy. What I want to do is grab the information from these modified objects and record them into the database. Now I have something like this:
Dim audit as History
audit.action = "Changed information in " & propName & " to " & entry.CurrentValues(propName) & " from " & entry.OriginalValues(propName)
audit.action_by = this_user
audit.action_date = Date.Now
audit.extension_id =
I'm not sure, however, how to tell it to pull a specific property from entry. For example, I need to get (pseudo-code) something like:
audit.extension_id = entry.OriginalValues(extension_id)
I don't understand what do you mean by "pulling a specific property from an entry"? The (pseudo) code you wrote is not telling much, what is an extesion_id in your case? If extension_id is a property name of an entity, then you obtain it's original value by calling entry.OriginalValues("extension_id"), but I'm fairly sure you knew that.
Btw, you can do intricate history recording in the DB itself using triggers without the data layer even knowing it. It's a fairly old trick and works fast, see this
Here is how I accomplished it in the end:
Private Shared Sub context_SavingChanges(ByVal sender As Object, ByVal e As EventArgs)
' This allows us to record a history of the changes made by the user to the database. The record is created automatically by EF, but we need to save it to the database
' for permanent retention.
For Each entry As ObjectStateEntry In DirectCast(sender, ObjectContext).ObjectStateManager.GetObjectStateEntries(EntityState.Modified)
If Not entry.IsRelationship And entry.Entity IsNot Nothing Then
For Each propName As String In entry.GetModifiedProperties()
Dim context As New AppsEntities()
Dim audit As New History
audit.action_note = "Changed information in " & propName & " to " & entry.CurrentValues(propName) & " from " & entry.OriginalValues(propName)
audit.action_by = CStr(HttpContext.Current.Session("person_name"))
audit.action_date = Date.Now
audit.extension_id = entry.CurrentValues.GetValue(0)
context.AddToHistories(audit)
context.SaveChanges()
Next
End If
Next
End Sub

Resources