问题描述
我有一个表,其中包含以下字段 ID IDuser IDpc FROM TO。 显然,一台 PC 不能被多个用户在同一时间段内使用。我如何对条目施加约束以防止错误的条目? 我在 asp.net 中使用 sql Server 2016(管理工作室)
解决方法
好的,正如前面提到的,我虽然关于使用同一台 PC 的多个用户的部分与多用户数据库有关!
我现在看到您正在预订要使用的 PC,并且您不希望预订冲突。
好的,有一个非常简洁的条件来测试/检查预订冲突。
看起来像这样: 在以下情况下发生碰撞:
RequestStartDate <= EndDate
and
RequestEndDate >= StartDate
如果值包括日期 + 时间,那么上述仍然可以正常工作。
上述条件会发现任何类型的重叠(因此中间的日期/时间)或任何重叠的部分。
正如我在评论中建议的那样?您可以获取/让数据库不允许您添加该行(您必须使用表触发器)。
但是,然后呢?
这真的暗示了什么?您不会写出记录并期望数据库出现故障。更糟糕的是,你真的想给用户一些不错的反馈。
因此,您的预订页面会询问房间,然后是开始/结束时间(带日期)。您使用上述条件,如果返回记录,则您告诉用户他们无法预订房间。但是,如果没有出现匹配项,则将该行添加到数据库中。
这种题其实看起来挺难的,但是有了上面的简单条件,却是异常的简单。
让我们将这个简单的例子作为一个 asp.net 网络表单。
因此,放入一个列表框、两个文本框(开始/结束)和一个书籍按钮。
因此,标记如下所示:
<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>
我投入了几个 div 来布局。
好的,现在加载列表框的代码是这样的:
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
现在我们明白了:
请注意,如果您放入该文本框并在属性表中选择 DateTimeLocal 作为格式,那么无需任何额外代码,您就可以免费获得很酷的日期 = 时间选择器。
现在,让我们编写代码来检查我们是否可以预订。
用户选择一个房间,然后选择开始/结束时间(可以是 1 小时,也可以是 1 周 - 没关系。
所以,现在我们的图书按钮代码如下所示:
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
注意这变得多么简单。我写这篇文章花了大约相同的时间?事实上,我有一个真正有效的预订页面。与上面的快速肮脏示例相比,它需要更多的关爱,但总而言之,上述方法的效果非常出色。
我们为列表框预订的计算机(桌子)是这样的:
然后预订表当然是这样的:
仅此而已。您可以看到我们查询了数据库,如果找到匹配项(冲突),那么我们甚至不会尝试添加该行,而是向用户提供该消息。
但是,如果现在找到了行,那么我们将该行添加到数据库中。
所以,它看起来像这样:
正是在这样的时刻,人们才意识到这在 asp.net 中是多么的简单。
享受吧!
仅供参考:“to”和“from”都是 SQL 词 - 你必须使用 [To] 和 [From](括号周围)这些词,因为 SQL Server 会混淆 - 这些列名是我们所说的保留单词 - 和“FROM”是常规 sql 语法的一部分,因此请记住在 sql 周围使用那些 []。