如果文本框为空,则在SQL中将日期时间字段设置为NULL

4
尝试将SQL表中的日期时间字段设置为NULL,如果文本框为空,则似乎无法使其正常工作。
        string EndDate = "";
        if (String.IsNullOrEmpty(EndDateTxtBox.Text.Trim()))
        {
            EndDate = null;
        }
        else
        {
            EndDate = EndDateTxtBox.Text;
        }

        var sql = String.Format(@"UPDATE Test SET StartDate='{0}', 
                                 EndDate='{1}' WHERE ID = '{2}'",
                                 StartDateTxtBox.Text, EndDate, id);

当我这样做并设置断点时,"var sql"的结果如下:
"UPDATE Test SET StartDate='5/23/2013', EndDate=" WHERE ID = '19'"

我尝试将 SQL 字符串中的 ' 移除,但也没有起作用。有什么建议吗?

编辑:我理解防止 SQL 注入的重要性,但这是我内部网站上的页面,只为我个人使用,不对外公开。它是帮助我追踪个人事务的工具。


22
一起说吧:不要将用户输入连接到 SQL 中 - Marc Gravell
OP,一个提示,看一下你在帖子中的SQL格式。要么你复制到帖子中出了问题,要么这是一个小提示,你的SQL语句有严重错误。 - Arran
@MarcGravell,为什么你总是要成为理性的代言人呢? :D - Mike Perrenoud
1
@kcray,StartDateEndDate所存储的列是什么格式?请不要告诉我是VARCHAR... - Arran
这是一次巨大的学习经历,谢谢大家。 - techora
5个回答

12

参数化。

首先,您应该将UI代码与数据库代码分离,这样在靠近数据库之前,我们就可以拥有正确类型的数据。例如:

void UpdateDates(int id, DateTime startDate, DateTime? endDate) {...}

将任何你想要的Parse等代码放在调用者处,而不是靠近数据库。现在我们需要实现它:

void UpdateDates(int id, DateTime startDate, DateTime? endDate) {
    //... where-ever cmd comes from, etc
    cmd.CommandText =
        "update Test set StartDate=@start, EndDate=@end where ID = @id";
    cmd.Parameters.AddWithValue("id", id);
    cmd.Parameters.AddWithValue("start", startDate);
    cmd.Parameters.AddWithValue("end", (object)endDate ?? DBNull.Value);
    cmd.ExecuteNonQuery();
    // ... cleanup etc
}

或者使用类似 "dapper" 的工具:

void UpdateDates(int id, DateTime startDate, EndDate? endDate) {
    //... where-ever connection comes from, etc
    connection.Execute(
        "update Test set StartDate=@start, EndDate=@end where ID = @id",
        new { id, start = startDate, end = endDate}); // painfully easy
    // ... cleanup etc
}

+1:当然,你必须提供一个更加强大的解决方案!你让我感到骄傲! - Mike Perrenoud

1
似乎问题在于单引号。如果为NULL,则不应该使用它们。
另外,出于安全原因并传递值,您可能想使用参数化查询。在这种情况下,引号也不是必需的。

当我发表我的回复时,我没有看到Michael Perrenoud的回复,但他的答案就是我所指的。 - Mike Cheel

0
你可以尝试这种方式:
string sql = String.Format(@"UPDATE Test SET StartDate={0}, 
                                     EndDate={1} WHERE ID = {2}",
                     (StartDateTxtBox.Text.Trim().Equals(string.Empty) ? StartDateTxtBox.Text:"NULL"), EndDate, id);

0

我认为错误出在 string.format 行。你不能在字符串部分包含换行符。请尝试以下方法之一。

 var sql = String.Format(
          @"UPDATE Test SET StartDate='{0}', EndDate='{1}' WHERE ID = '{2}'",
           StartDateTxtBox.Text, EndDate, id);

或者,

    var sql = String.Format(@"UPDATE Test SET StartDate='{0}', " + 
                             "EndDate='{1}' WHERE ID = '{2}'",
                             StartDateTxtBox.Text, EndDate, id);

但是,正如其他答案所提到的,你应该学习关于SQL注入的知识,并考虑另一种方法。


6
请不要鼓励更多的 SQL 注入可能性。 - Lasse V. Karlsen
@Michael,是的,SQL注入很重要。而且该操作应尽快了解它以及如何编写代码来防范它。但是我在这里尝试根据提问者的专业水平来回答问题。从新手到专业处理安全问题是一个陡峭的学习曲线。我们怎么知道这个应用程序做什么,在哪里运行,安全漏洞的后果是什么等等? - Charles Bretana
只是提醒一下,如果有关系的话,这是一个仅供我使用的内部网络站点。我想我应该说明一下。除了我之外,没有人能够访问它。 - techora
1
@CharlesBretana,我完全理解你的立场,并且我没有对你的回答进行投票,但我的立场是这样的。你练习的方式就是你的表现方式。如果你编写一个仅供自己使用但允许 SQL 注入的本地应用程序,那么你将会以同样的方式编写其他应用程序。此外,“难道我不是我兄弟的守护者吗?”更合适的是我引导我的兄弟走上更好的道路,还是让他被汽车撞击?因此,正如我所说,这里“学究式”并不是正确的词。 - Mike Perrenoud
@Michael,哈!我想我不同意你的看法。除非他/她问我,否则我不是我兄弟的监护人!但是,说真的,如果你正在学习如何系鞋带,那么有些PETA疯子向你讲述使用皮鞋是对动物的道德罪行是没有帮助的。不要说这是荒谬的例子,它只是在同一范围内更进一步。 - Charles Bretana
我们不是在谈论系鞋带的问题。我们在谈论有人拿着一支上膛的猎枪,对准了自己的脚。你不会告诉那个人如何扣动扳机。但没关系。 - Lasse V. Karlsen

0

尽管您的代码中存在一些不符合C#代码中SQL最佳实践的问题,但您还有几个问题:

  1. 您将EndDate设置为C# null。这与表示为DBNull.Value的SQL NULL不同。

  2. 您没有考虑到在SQL中NULL不需要引号,因此即使您修复了问题#1,您的SQL也需要进行不同的更改才能正常工作。

我建议编写存储过程;如果结束日期文本框为空,则不要传递该参数,并在存储过程中将其默认值设置为NULL。

Create Procedure usp_TestDateRange_Update
( @ID int -- or whatever type your ID is
  @StartDate DateTime,
  @EndDate DateTime = NULL)
As 
  Update Test
  Set StartDate = @StartDate,
      EndDate = @EndDate
  Where ID = @ID

就像这样。现在你需要做的是让你的C#代码调用存储过程,并从你的文本框中添加参数到调用中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接