我有一个表,其中记录了进程,我想创建一个控制台应用程序,一旦消息写入该表,该应用程序就会循环并更新控制台。
最终的结果将是我查看控制台,而不是查询数据库。
我有一个可以提取数据并显示的查询,但我正在寻找最佳实践/更好的解决方案,因为我觉得我的不符合标准
string ConnectionString = "connectionstring here";
string TableName = "table name here";
while (true)
{
SqlConnection myConnection = new SqlConnection(ConnectionString);
myConnection.Open();
SqlDataReader myReader = null;
SqlCommand myCommand = new SqlCommand("select LogDate, Message from " + TableName + " where convert(date, logdate, 103) = convert(date, getdate(), 103) order by logdate;", myConnection);
myReader = myCommand.ExecuteReader();
while (myReader.Read())
{
Console.WriteLine(myReader["LogDate"].ToString() + " -> " +
myReader["Message"].ToString());
//Thread.Sleep(200);
}
myConnection.Close();
}
我觉得值得一提的三件事:
- 通过连接不受控制的值来构建动态SQL时要小心。如果
TableName
的中间有一个空格(或者更糟的是,像TableName; DECLARE @CurrentLogin VARCHAR(100) = SYSTEM_USER; EXEC('DROP LOGIN ' + @CurrentLogin);
这样的SQL命令,不执行!),会发生什么。由于您正在动态更改表,因此无法对该查询进行参数化,尽管您可以做一些事情来降低注入风险,例如确保TableName
变量少于X个字符(通常20个就足够了),并且不包含空格、分号或关键SQL字(如EXEC
或DROP
) - 您正在选择和筛选特定的列,因此此查询不能用于大多数表,只能用于具有这些列的表。您应该考虑删除动态表参数,转而使用
Switch
,只允许查询要查询的表。这将使您的查询受到限制,但更安全 -
在与常量(
getdate()
)进行比较之前,您的筛选器正在转换表列(logdate
),这将使logdate
上的索引(如果有的话)不适用。我相信你想查看当天的记录,所以你正在对日期代码103
(yyyy-MM-dd
)进行比较。您应该避免转换表值,而是使用双过滤器,假设logdate
是DATETIME
。如果logdate
的日期不能高于今天,您可以跳过第二次检查:WHERE logdate >= CONVERT(DATE, GETDATE()) AND logdate < CONVERT(DATE, GETDATE() + 1) ORDER BY logdate
最终结果将是我查看控制台而不是查询数据库。
控制台将为您查询数据库,您只是在更改用户界面。
如果你有很多控制台日志,你可以通过datetime
进行动态过滤,而不是每次都查询所有的当前日期。因此,每个查询都会带来您查询的最后一个datetime
的记录,从而带来所有新的记录。您可以添加一个完整的datetime
参数,只检索比前一个更高的记录,并将当前日期时间存储在此变量中。
您可以使用SqlDependency在发生更改时通知您的应用程序,而不是使用pull模型并重复查询数据(即使没有更改)。此链接包含概述和示例。
不过需要注意的一点是,SqlDependency
对象是在考虑服务器应用程序的情况下构建的。它并不意味着要推广到许多正在倾听变化的客户。有关其他信息,请参阅此链接。