【问题标题】:Npgsql DataReader uses DateTime type for time without time zone rather than TimeSpanNpgsql DataReader 使用 DateTime 类型来表示没有时区的时间,而不是 TimeSpan
【发布时间】:2015-09-14 18:32:04
【问题描述】:

我正在使用 Npgsql 从 Postgres 中的表中进行选择。此表有一个列auction_time,其类型为time without time zone。读者返回的数据表将此列auction_time 转换为DateTime,而不是我期望的TimeSpan。将数据批量复制到 MS SQLServer 中 time(7) 类型的另一个表时,这会导致问题。

这里是我选择的地方:

using (NpgsqlConnection connection = new NpgsqlConnection(String.Format(PropertyDataDB.ConnectionStringWithSearchPath, schemaName)))
{
    connection.Open();
    NpgsqlCommand command = new NpgsqlCommand
    {
        CommandText = commandText,
        Connection = connection
    };

    using (NpgsqlDataReader dataReader = command.ExecuteReader())
    {
        DataTable dt = new DataTable();
        //dt = dataReader.GetSchemaTable();
        dt.Load(dataReader);

        BulkCopy(destinationTable, dt);
    }
}

所以 dt 中的 auction_type 将是 DateTime 类型,并且所有时间都会在其前面附加日期 1/1/0001。我怎样才能防止这种情况发生?

谢谢。

【问题讨论】:

  • 这是 .NET/PSQL 类型的转换表 - npgsql.org/doc/datetime.html。似乎 Time w/o TZ 确实列出了时间跨度。也许有一个错误需要报告(或者文档不清楚)?
  • 我在 github 上提交了一个错误,他们同意这是 2.2.5 版本中的错误,但在 3.x 版本中已修复。不幸的是,3.x 中有一些重大变化。
  • 您有指向重大更改列表的链接吗?我也在 2.x 上,但我似乎找不到完整的列表,只是一些不完整的里程碑列表。
  • 下面我的一个答案有一个指向 3.0 迁移文档的链接。

标签: c# postgresql npgsql


【解决方案1】:

另一个修复是将 Npgsql 升级到 3.x 版本,这个问题已经修复。 http://www.npgsql.org/doc/release-notes/3.0.html

【讨论】:

    【解决方案2】:

    这就是我最终做的事情,只有在您需要保持在 2.x 版本时才做这样的事情。它有效,但我根本不喜欢它。我只是克隆数据表,更改数据类型,并在需要时执行“强制转换”。

    using (NpgsqlConnection connection = new NpgsqlConnection(String.Format(PropertyDataDB.ConnectionStringWithSearchPath, schemaName)))
    {
        connection.Open();
        NpgsqlCommand command = new NpgsqlCommand
        {
            CommandText = commandText,
            Connection = connection
        };
    
        using (NpgsqlDataReader dataReader = command.ExecuteReader())
        {
            DataTable dt = new DataTable();
            dt.Load(dataReader);
    
            if (dt.Columns.Contains("auction_time"))
            {
                DataTable clone = dt.Clone();
                clone.Columns["auction_time"].DataType = typeof(TimeSpan);
                foreach (DataRow row in dt.Rows)
                {
                    DataRow newRow = clone.NewRow();
                    foreach (DataColumn column in dt.Columns)
                    {
                        if (column.ColumnName == "auction_time" && !row.IsNull(column.Ordinal))
                        {
                            newRow[column.Ordinal] = ((DateTime)row[column.Ordinal]).TimeOfDay;
                        }
                        else
                        {
                            newRow[column.Ordinal] = row[column.Ordinal];
                        }
                    }
                }
                dt = clone;
            }
    
            BulkCopy(destinationTable, dt);
        }
    }
    

    【讨论】:

      【解决方案3】:

      我的解决方案:

      class Model
      {
          public readonly static string tableName = "tb_name";
          public Int32 id {get; private set;}
          public string auth_token {get; private set;}
          public TimeSpan column_time {get; set;} // this is the target !!
      
          /* more columns for model object   here.. */
      
          public static NpgsqlCommand Query(string sql = null )
          {
              // treturn new NpgsqlCommand from my global NpgsqlConnection  definition
              return Connection.CreateObject().Query(sql); 
          }
      
          public static Model FindByPk(int id)
          {
              NpgsqlCommand query = Query(string.Format("select  * from {0} where id = @id order by id asc limit 1" , tableName ));
              query.Parameters.AddWithValue("@id", id);
      
              NpgsqlDataReader reader = query.ExecuteReader();
              if(reader.HasRows == false)
                  return null;
      
              Model obj = new Model();
              return (obj.SetDbProperties(reader)) ? obj : null;
          }
      
          protected bool SetDbProperties(NpgsqlDataReader reader)
          {
              if(reader.IsClosed)
                  return false;
              try{
                  reader.Read();
      
                  for (int i = 0; i < reader.FieldCount; i++)
                  {
                      string key = reader.GetName(i);
      
                      if(reader.GetValue(i) == DBNull.Value )
                          continue;
      
                      //@todo add dinamic setter by key value
                      // https://titiandragomir.wordpress.com/2009/12/22/getting-and-setting-property-values-dynamically/
                      switch(key)
                      {
                          case "id":
                              this.id =  reader.GetInt32(i);
                              break;
                          case "auth_token":
                              this.auth_token = reader.GetString(i);
                              break;
      
                          case "column_time":
                                  // solution!!!!
                                  var colValue = reader.GetTime(i);
                                  this.horario_dia1_init = new TimeSpan(0, colValue.Hours , colValue.Minutes, colValue.Seconds, colValue.Microseconds ); 
                              break;
                      }
                  }
                  reader.Close();
                  return true;
              }
              catch(Exception e){
                  Console.WriteLine(e.Message);
                  return false;
              }
          }
      }
      

      使用示例:

          public static void Main(string[] args)
          {
      
              Model model = Model.FindByPk(1);
              if(model == null)
                  Console.WriteLine("record not found");
      
              else {
                  Console.WriteLine("model.id               {0}", model.id);
                  Console.WriteLine("model.auth_token       {0}", model.auth_token);
                  Console.WriteLine("model.column_time      {0}", model.column_time); 
              }
      
              Console.Read();
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-17
        • 2015-11-09
        • 2015-11-26
        • 2023-03-14
        • 2019-11-08
        • 2023-04-11
        • 2021-06-18
        • 2021-12-27
        相关资源
        最近更新 更多