我之前没有在实践中使用过 SQL 依赖关系,但据我了解,
DependencyOnChange
当我运行下面的 SQL 更新语句时应该触发事件。
澄清一些细节:
is_broker_enabled
= 1db_owner
SqlDependency_Register
在页面按预期加载时运行。DependencyOnChange
时,不会命中 MyCol
上的断点。此时任何建议或指导将不胜感激,因为我已经用尽了我能找到的所有研究选项。
SQL
UPDATE [dbo].[MyTable] SET [MyCol] ='test' WHERE [id] = 1`
VB.NET
Private Sub Page_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
If Not IsPostBack Then
SqlDependency_Register()
End If
End Sub
Protected Sub Page_Unload(sender As Object, e As EventArgs) Handles Me.Unload
SqlDependency.Stop(ConfigurationManager.ConnectionStrings("CON").ConnectionString)
End Sub
Public Sub SqlDependency_Register()
Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("CON").ConnectionString)
Using cmd As New SqlCommand("SELECT [MyCol] FROM [dbo].[MyTable]", con)
Dim dependency As New SqlDependency(cmd)
AddHandler dependency.OnChange, AddressOf DependencyOnChange
SqlDependency.Start(ConfigurationManager.ConnectionStrings("CON").ConnectionString)
con.Open()
cmd.ExecuteReader()
End Using
End Using
End Sub
Private Sub DependencyOnChange(sender As Object, e As SqlNotificationEventArgs)
If e.Info = SqlNotificationInfo.Update Then
Console.WriteLine(e.Info)
End If
SqlDependency_Register()
End Sub
目标
当 sql 中的数据值发生变化时,在页面上显示数据的实时更新(例如通过另一个用户)。我了解通过 Signalr 从服务器向客户端发送数据,但不了解如何让 .Net 应用程序检测 SQL 中的更改。
也许有比 SQLDependency 更好的方法?
好吧,请记住,给定页面的后台代码超出了范围,并在页面发送到客户端后立即被删除、处置和从内存中删除。
如前所述,您可以考虑使用 SignalR,但您不能坚持认为给定网页背后的代码存在。它仅在回发期间存在。一旦页面发送到客户端,代码、变量和所有内容都会从内存中删除。 Web 服务器与桌面软件不同,每个用户都有一组持久的代码和变量。
在网络领域,这个术语是“无状态”。这意味着您可以将网页(及其代码)视为调用子例程。当您退出该子例程时,该子例程中的所有代码和变量都会消失,并超出范围。您的网页代码的工作方式相同 - 它仅在短回发期间存在。一旦后台代码完成运行并将页面发送回客户端,那么所有后台代码现在都会超出范围,从内存中删除,并且不会持久存在。
所以,最简单的解决方案是确保数据库有行版本值。当该行数据更新时,该值也会更改。
因此,一个简单且可行的方法是让一些客户端代码调用 Web 方法,并返回行版本值的 sum()。如果发生任何更新、删除或插入,则该值将会更改。
但是,如前所述,您不能让 SQL Server 事件调用您的页面代码,因为正如我所指出的,页面代码(页面类)不存在于内存中,并且在页面发送到后立即从内存中删除。客户端。
因此,我想您可以启动一个单独的进程,该单独的进程可以跟踪页面是否已更改,然后当然使用 SignalR,然后就可以工作了。但是您不能使用给定网页的后台代码来监视此类数据库事件,因为后台代码不在内存中也不再运行。
除非您想采用一些复杂的 SignalR 代码并保持进程在服务器端运行?
然后我建议在该给定页面上使用一个简单的 Web 方法,并让客户端检查更改,例如每 1 或 2 秒检查一次。
所以,这是一个有效的示例:
标记:
<asp:GridView ID="GVHotels" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-hover"
Width="50%">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel" />
<asp:BoundField DataField="Description" HeaderText="Descriptioin" />
</Columns>
</asp:GridView>
<asp:HiddenField ID="MyChanged" runat="server" Value="0" ClientIDMode="Static" />
<asp:Button ID="cmdReload" runat="server" Text="Reload grid"
OnClick="cmdReload_Click" />
</div>
<script>
var MyTimer
$(window).on("load", function () {
MyTimer = setInterval(checkchanged, 2000)
});
function checkchanged() {
$.ajax({
url: "Hotels.aspx/GetChanged",
data: {},
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data.d != $('#MyChanged').val()) {
$('#cmdReload').click()
}
}
});
}
</script>
背后的代码:
Imports System.Web.Services
因此:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData() ' first time grid load
End If
End Sub
Sub LoadData()
Dim rstData As DataTable
Dim strSQL As String =
"SELECT *, cast(ts as bigint) as checksum FROM tblHotelsA
ORDER BY HotelName"
rstData = MyRst(strSQL)
GVHotels.DataSource = rstData
GVHotels.DataBind()
Dim checksum As ULong = 0
For Each dr As DataRow In rstData.Rows
checksum += dr("checksum")
Next
MyChanged.Value = checksum
End Sub
Protected Sub cmdReload_Click(sender As Object, e As EventArgs)
LoadData()
End Sub
<WebMethod>
Public Shared Function GetChanged() As String
Dim rstData As DataTable
Dim strSQL As String =
"SELECT sum(cast(ts as bigint)) as checksum FROM tblHotelsA"
rstData = MyRst(strSQL)
Dim Result As ULong = rstData.Rows(0)(0)
Return Result.ToString
End Function
所以,结果是这样的:
因此,当数据发生更改(更新、删除或编辑)时,GridView 将重新加载。我使用 jQuery .click() 事件单击页面上的按钮进行刷新,当然该按钮可以(应该)隐藏,如下所示:
<asp:Button ID="cmdReload" runat="server" Text="Reload grid"
OnClick="cmdReload_Click"
style="display:none"
/>
所以,我认为上述内容比采用 SignalR 并推送到浏览器要少得多。即使您确实采用 SignalR,您仍然无法让给定页面的后台代码从 SQL Server 订阅某些“事件”,因为如上所述,页面类(后台代码)不存在并且立即脱离上下文页面已发送至客户端。
您注意到我向网页添加了一个 Web 方法,但它是一个“静态”方法,因此必须标记为“共享”(在 VB.NET 中),或者在 C# 中标记为静态,因为调用该 Web 方法时,不会创建页面类(隐藏代码)。