【问题标题】:SQL Server :DateTime Data Causing Exception Error with DateTime.TodaySQL Server:DateTime 数据导致 DateTime.Today 异常错误
【发布时间】:2018-07-18 22:04:02
【问题描述】:

我创建了以下导致错误状态的序列

System.IndexOutOfRangeException: '索引超出了数组的范围。'

如 cmets 所示。

SqlCommand cmd = new SqlCommand(@"SELECT GETDATE() 'Today', DATENAME(weekday, GETDATE()) 'Day Name'; 
          select * from [Schedule] where Working = datename(weekday,GetDate()) and Commencing != Finishing; 
          select * from [Vacation] where VacStart = GetDate();", con);

con.Open();

SqlDataReader read = cmd.ExecuteReader();
DateTime now = DateTime.Today;

while (read.Read())
{
    // from Schedule Table
    string Working = read.GetString(1);
    DateTime Commencing = read.GetDateTime(2); //Exception Error Here
    DateTime Finishing = read.GetDateTime(3); //Exception Error Here

    // from Vacation Table
    string Reason = read.GetString(1);

    if (Reason == null)
    {
        // if condition is met
        lblMsg2.Text = "<p class='closed'>Sorry, we are closed for for a personal holiday.<br />If you are a current client and this is an emergency, we will of course make every effort to accommodate you.</p>";
    }
    else
    {
        // if condition is not met
        if (Working != null && now >= Commencing && Finishing <= now)
        {
            // if condition met
            lblMsg2.Text = "<p class='open'>Yes, we are currently open and would love to hear from you!</p>";
        }
        else
        {
            // if condition is not met
            lblMsg2.Text = "<p class='closed'>Sorry, we are currently closed. You can reach us during normal business hours. We would love to have the opportunity to speak with you!</p>";
        }
    }
}

根据我对大量帖子的研究,我认为错误是由日期差异引起的,即 1900-01-01 与 2018-07-18。日期不相关,因为我只是想比较时间。

我尝试了几种变体,您可以在其中更改查询以考虑日期,但我无法让这些工作。

看起来每个人都将数据从 DateTime 转换为字符串,我也很难开始工作。

CommencingFinishing 列在 SQL Server 数据库中都是 DateTime 类型。

【问题讨论】:

  • 您已经编写了三个 SELECT 命令。读取器在完成读取第一个 SELECT 的结果之前不能使用第二个 SELECT 的结果。第一个选择中没有第三个字段,第二个选择也是如此。
  • mjwills, cmets 是我的笔记,这样我就可以记住数据与哪些表相关联,即 Working、Starting 和 Finishing 都是 Schedule 表中的表,等等。这就是全部意思由那些。
  • 谢谢史蒂夫!这有帮助。我删除了第一个选择查询,列出了我想读取的字段,以便剩余的两个选择都提取相同数量的结果列。它现在可以按我的意愿工作,并且消息正在发布。
  • 尝试删除 dataReader 并使用 DataAdapter:docs.microsoft.com/en-us/dotnet/framework/data/adonet/… 然后您可以使用诸如 Commencing = Table[1] & Finishing = Table [2] 之类的东西 - 即使这两个表只包含一条记录

标签: c# sql-server exception


【解决方案1】:

SqlCommand 中的查询包含 3 个选择语句,因此它将返回 3 个行集。您遇到的问题是发布的代码仅处理第一个行集;但评论表明您认为它正在处理第二个和第三个。我的解决方案如下;但这里列出了一些改进建议。

  1. SqlCommandSqlDataReaderSqlConnection 都是 IDisposable,所以每个都应该在 using 块中。 (我接受我在发布的代码中看不到连接,我只是在猜测。)
  2. 根据 cmets,您似乎不关心 3 个查询中的第一个,所以不要让 SQL 来做。
  3. 避免使用select *。如果您专门编写了您期望的列,那么您的代码将受到保护,不会对数据库进行更改,例如更改列的顺序或向表中添加新列。它还可以帮助您检查代码,因为您将能够检查每个序数所指的列。
  4. 鉴于您已经完成了select *无法确定您是否知道 DataReader 上的 Get 方法的序号从零开始,而不是 1,所以我想我应该提一下它 - 如果有问题,您需要修复它。
  5. 如果一列返回null,那么你不能Get它,你需要对相同的序数使用IsDbNull方法。您可以将这两个调用封装在一个扩展方法中。如下所示。
  6. 我建议将read(动词)重命名为reader(名词)。
  7. 要从一个结果集前进到下一个结果集,请使用NextResult()

这里是扩展方法,其他类型可以做类似的方法:

public static class DataRecordExtensions
{
    public static string GetNullableString(this IDataRecord dataRecord, int ordinal)
    {
        return dataRecord.IsDBNull(ordinal) ? null : dataRecord.GetString(ordinal);
    }
}

注意:我无法从 sn-p 中得知查询返回了多少行,所以我只使用了 while 循环。我已将逻辑转移到更接近相关代码;但它应该表现相同。无论如何,逻辑可能需要修复,因为我不知道返回了多少行。

    using (SqlCommand cmd = new SqlCommand(@"select * from [Schedule] where Working = datename(weekday,GetDate()) and Commencing != Finishing; 
      select * from [Vacation] where VacStart = GetDate();", con))
    {
        con.Open();

        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            DateTime now = DateTime.Today;

            // from Schedule Table
            while (reader.Read())
            {
                string working = reader.GetString(1);
                DateTime commencing = reader.GetDateTime(2);
                DateTime finishing = reader.GetDateTime(3);

                // if condition is not met
                if (working != null && now >= commencing && finishing <= now)
                {
                    // if condition met
                    lblMsg2.Text = "<p class='open'>Yes, we are currently open and would love to hear from you!</p>";
                }
                else
                {
                    // if condition is not met
                    lblMsg2.Text = "<p class='closed'>Sorry, we are currently closed. You can reach us during normal business hours. We would love to have the opportunity to speak with you!</p>";
                }
            }

            // from Vacation Table
            if (reader.NextResult())
            {
                while (reader.Read())
                {
                    string reason = reader.GetNullableString(1);
                    if (reason == null)
                    {
                        // if condition is met
                        lblMsg2.Text = "<p class='closed'>Sorry, we are closed for for a personal holiday.<br />If you are a current client and this is an emergency, we will of course make every effort to accommodate you.</p>";
                    }
                }
            }
        }

【讨论】:

  • 我会尽量在这里提供清晰的说明。两个表只有 4 列。 Schedule 表返回 Id、Working、Starting 和 Finishing,并且只包含 7 行。假期表返回假期的原因,即假期的名称,以及开始和结束日期,到目前为止有 13 行。如果假期不包括“今天”,那么我需要它来运行正常的打开与关闭。但是如果“今天”在开始和结束日期的假期范围内,那么它应该忽略正常的打开与关闭。那么,它不应该先读取假期表吗?
  • 它会按原样工作,因为假期逻辑在调度逻辑之后,所以如果它适用,那么它将覆盖lblMsg2.Text 中的值。你可以让它先阅读假期,如果你正在度假,不要打扰日程安排。为了正确地做到这一点,我什至建议您将这两个单独的 SQL 查询拆分为两个单独的方法,每个方法都返回一个简单的属性包对象列表 - 这样您就可以分离关注点,并且您不会要求 SQL花时间获取您实际上并没有使用的数据。但我正在回答提出的问题。
  • P.S. “我们因个人假期而休息”中有一个重复的词。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-10
  • 2017-11-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多