为什么我在尝试转换时间戳时收到超出范围的消息

本文关键字:范围 消息 时间戳 转换 为什么 | 更新日期: 2023-09-27 18:35:18

所以我有以下代码:

listOfUserLogs.Add(new Log { TimeStamp = Convert.ToDateTime(myReader["TimeStamp"]), CheckpointId = Convert.ToInt32(myReader["CheckpointId"]) });

当我运行该程序时,我得到了System.IndexOutOfRangeException {"TimeStamp"}.我不明白为什么会这样以及如何解决它.

注意:我编辑了帖子,以便您可以看到整个代码并让我知道我错过了什么。

你可以在这里看到我的程序:

namespace Distance
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString = GetConnectionString();

            using (SqlConnection sourceConnection =
                       new SqlConnection(connectionString))
            {
                sourceConnection.Open();
                SqlDataReader myReader = null;
                SqlCommand myCommand = new SqlCommand("SELECT User.Id , [Log].[TimeStamp] ,[Checkpoints].[Id] ,[Checkpoints].[Coordinates] FROM dbo.[Users] INNER JOIN dbo.[Log] ON [Log].[UserId] =[Users].[Id] INNER JOIN dbo.[Checkpoints] ON [Checkpoints].[Id] = [Log].[CheckpointId] ", sourceConnection);
                //SqlCommand myCommand = new SqlCommand("SELECT User.Id ,User.Name ,Checkpoint.Id ,Checkpoint.Coordinates , Log.TimeStamp FROM dbo.Users, INNER JOIN dbo.Log ON Log.UserId = User.Id, INNER JOIN dbo.Checkpoints ON Checkpoint.Id = Log.CheckpointId ;", sourceConnection);
                myReader = myCommand.ExecuteReader();
                var listOfUsers = new List<User>(); //get users from db
                //long countStart = System.Convert.ToInt32(myCommand.ExecuteScalar());
                var listOfCheckpoints = new List<Checkpoint>(); //get checkpoints from db
                var listOfUserLogs = new List<Log>();
                while (myReader.Read())
                {
                    listOfUsers.Add(new User
                    {
                       Id = Convert.ToInt32(myReader["Id"]),
                       Name = myReader["Name"].ToString(),
                       Coordinates = myReader["Coordinates"].ToString()
                    });
                    listOfCheckpoints.Add(new Checkpoint
                    {
                        Id = Convert.ToInt32(myReader["Id"]),
                        Coordinates = myReader["Coordinates"].ToString()
                    });
                    listOfUserLogs.Add(new Log
                    {
                        TimeStamp = Convert.ToDateTime(myReader["TimeStamp"]),
                        CheckpointId = Convert.ToInt32(myReader["CheckpointId"]),
                        UserId =Convert.ToInt32(myReader["UserId"])
                    });
                }

            StringBuilder sb = new StringBuilder();
            foreach (var user in listOfUsers)
            {
                string address = user.Coordinates;
                DateTime currentDate = new DateTime(2014, 8, 1);
                var dictionary = new Dictionary<string, double>();
                while (currentDate <= DateTime.Now)
                {
                    double dayUserDistance = 0.00;
                   // var listOfUserLogs = new List<Log>(); //Get logs where day == currentDate from db
                    var previousCoordinate = address;
                    foreach (var log in listOfUserLogs)
                    {
                        Checkpoint checkpoint = listOfCheckpoints.FirstOrDefault(x => x.Id == log.CheckpointId);

                        dayUserDistance += DistanceCalculator.GetDistance(previousCoordinate, checkpoint.Coordinates);
                        previousCoordinate = checkpoint.Coordinates;
                    }
                    dayUserDistance += DistanceCalculator.GetDistance(previousCoordinate, address);
                    dictionary.Add(currentDate.ToString("yyyy-MM-dd"), dayUserDistance);
                    currentDate = currentDate.AddDays(1);
                }
                sb.Append(user.Name + ";");
                foreach (KeyValuePair<string, double> keyValuePair in dictionary)
                {
                    sb.Append(keyValuePair.Value + ";");
                }
                sb.AppendLine();
            }
            Console.WriteLine();
            Console.ReadLine();
            }
        }
                 private static string GetConnectionString()
                // To avoid storing the sourceConnection string in your code,  
                // you can retrieve it from a configuration file. 
                {
                    return "Data Source=BESA-PC;" +
                        " Integrated Security = true;" +
                        "Initial Catalog=CykelScore2;";
                }
        }
    }
internal class DistanceCalculator
    {
        public static double GetDistance(string previousCoordinate, string coordinates)
        {
            string[] PairSequence = previousCoordinate.Split(',');
            float sLatitude = float.Parse(PairSequence[0]);
            float sLongitude = float.Parse(PairSequence[1]);
            string[] PairSequence2 = coordinates.Split(',');
            float eLatitude = float.Parse(PairSequence2[0]);
            float eLongitude = float.Parse(PairSequence2[1]);

            var sCoord = new GeoCoordinate(sLatitude, sLongitude);
            var eCoord = new GeoCoordinate(eLatitude, eLongitude);

            return sCoord.GetDistanceTo(eCoord);
        }
    }
    internal class Checkpoint
    {
        public int Id { get; set; }
        public string Coordinates { get; set; }
    }
    internal class Log
    {
        public DateTime TimeStamp { get; set; }
        public int CheckpointId { get; set; }
        public int UserId { get; set; } 
    }
    internal class User
    {
        public int Id { get; set; }
        public string Coordinates { get; set; }
        public string Name { get; set; }
    }

为什么我在尝试转换时间戳时收到超出范围的消息

上面的代码中有很多问题。基本上,您正在尝试按照表的确切模型对类进行建模,这并不总是最佳路径。
例如,我会以这种方式设计您的类

(为了避免新类坐标和字符串坐标之间的命名混淆,我将后者重命名为位置)

internal class Coordinate
{
    public int coordID { get; set; }                // This is your CheckpointID
    public string Location { get; set; }            // This is the string coordinate loaded 
    public DateTime TimeStamp { get; set; }         // This is the TimeStamp of the coordinate
}
internal class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Coordinate> Coordinates {get;set;}
}

有了这些更改,我会以这种方式修改您的查询

@"SELECT User.Id AS UserID, 
        [Log].[TimeStamp],
        [Checkpoints].[Id] as CheckPointID,
        [Checkpoints].[Coordinates] as Location 
  FROM dbo.[Users] INNER JOIN dbo.[Log] 
                        ON [Log].[UserId] = [Users].[Id] 
                   INNER JOIN dbo.[Checkpoints] 
                        ON [Checkpoints].[Id] = [Log].[CheckpointId]
  ORDER BY User.ID, [Log].[TimeStamp]"   <--- This order by is very important

此时,您的循环应该随着

User usr = null;
int curUserID = -1;
while (myReader.Read())
{
    int id = Convert.ToInt32(myReader["UserId"]);
    if(curUserID != id)
    {
        // Enter this block only if the user changes from the previous one
        // They are ordered so you are sure to get them in line
        usr = new User()
        {
             Id = id, 
             Name = reader["Name"].ToString(), 
             Coordinates = new List<Coordinate>()
        };
        curUserID = id;
        listOfUsers.Add(usr);
    }
    // Add all the coordinates that belong to the same user
    Coordinate cc = new Coordinate()
    {
        cc.coordID = Convert.ToInt32(reader["CheckPointID"]);
        cc.TimeStamp = Convert.ToDateTime(reader["TimeStamp"]);
        cc.Location = reader["Location"].ToString();
    };
    usr.Coordinates.Add(cc);
}

在此循环结束时,您可以在listOfUser上循环,并使用属于特定用户的List<Coordinate>计算距离,使用时间戳对他们进行排序

foreach(User usr in listUser)
{
    ...
    foreach(Coordinate cc in usr.Coordinates.OrderBy(x => x.TimeStamp)
    {
        ......
    }
}

话虽如此,我真的建议您花一些时间尝试学习现代ORM工具(实体框架,Dapper)的用法,该工具将删除所有代码以从数据库加载数据,并让您专注于任务所需的逻辑。