Home > Software design >  pwsh 7 format-default: Unable to cast object of type 'MySql.Data.Types.MySqlDateTime' to t
pwsh 7 format-default: Unable to cast object of type 'MySql.Data.Types.MySqlDateTime' to t

Time:08-04

I need to read data from mysql database with pwsh 7. On powershell 5 it is working fine but with pwsh 7 not with , and receive an error message when querying a table with 'timestamp' data :

"format-default: Unable to cast object of type 'MySql.Data.Types.MySqlDateTime' to type 'System.IFormattable'."

 [void][system.reflection.Assembly]::LoadWithPartialName("MySql.Data")
        $connStr = "server="   $MySQLHost   ";port="   $MySQLPort   ";uid="   $user   ";pwd="   $pass   ";database="   $MYSQLDatabase   ";Pooling=FALSE;Allow Zero Datetime=true;Allow User Variables=True;Connect Timeout=60"
        $conn = New-Object MySql.Data.MySqlClient.MySqlConnection($connStr)
        $conn.Open()
        New-Object MySql.Data.MySqlClient.MySqlCommand("USE $database", $conn)
        
    $query = "select Name, InputDate from ENVIRONMENT"
    $cmd = New-Object MySql.Data.MySqlClient.MySqlCommand($query, $conn)    
    $dataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter($cmd)
    $dataSet = New-Object System.Data.DataSet
    $dataAdapter.Fill($dataSet, "data")
    $cmd.Dispose() 
    
    $dataSet.Tables["data"]  

So I can see that after "$dataAdapter.Fill($dataSet, "data")" data are collected from mysql because it return the number of row. But after "$dataSet.Tables["data"]" it return the error.

In powershell 5 it is working fine.

Any help :-) ?

Thanks

CodePudding user response:

If your code works in Windows PowerShell, but not in PowerShell (Core) 7 , I encourage you to report an issue in the PowerShell GitHub repo.

However, you should first make sure that you're loading the .NET (Core)-appropriate version of the assembly (MySql.Data) from the MySql.Data NuGet package, given that [System.Reflection.Assembly]::LoadWithPartialName("MySql.Data") may be loading an older, .NET Framework-only version from the GAC (Global Assembly Cache), as would the equivalent - and preferable - form Add-Type -AssemblyName MySql.Data.

Unfortunately, using NuGet packages isn't well supported in PowerShell as of version 7.2.x:


Some thoughts about the error and a potential - slow - workaround:

MySql.Data.Types.MySqlDateTime indeed does not implement the System.IFormattable interface. It's unclear to me why this cast is even attempted or - in case the attempt is by design - why the exception isn't caught.

When PowerShell stringifies objects, it checks for whether they implement the IFormattable, so that a culture-invariant string representation can be requested. Conceivably, the bug has to do with mistakenly believing MySqlDateTime to implement this interface.

MySqlDateTime does have an explicit conversion operator to .NET's [datetime] (System.DateTime) type, which you should be able to use from PowerShell with a [datetime] cast.

Thus, the following approach may work as a workaround:

  • For a given table's rows, replace the MySqlDateTime-typed properties (columns) with properties that explicitly convert the values to [datetime], with the help of Select-Object and calculated properties.

  • Note that such an approach will be slow, because a new object must be constructed for each row, which also means that the type identity of the rows will be lost.

Note: The following is a simplified, self-contained example that simulates your MySQL data types; for simplicity, type [string] is used in lieu of [MySql.Data.Types.MySqlDateTime] to modify the columns of interest with an explicit [datetime] cast - adapt accordingly.

# These sample rows simulate the following:
#   $rows = $dataSet.Tables["data"]
$rows = @(
  [pscustomobject] @{ 
    foo = 1; 
    bar = '1970/01/01'
  },
  [pscustomobject] @{ 
    foo = 2; 
    bar = '1970/01/02'
  }
)

# Get the first row, so the data types of its properties (columns)
# can be analyzed.
# (I assume there's a way to do this directly via a table object,
#  and its column definitions, but I'm not familiar with the MySQL .NET API.)
$firstRow = $rows | Select-Object -First 1

# Construct an array of property names / calculated properties to pass
# to Select-Object below.
$propArray = foreach ($prop in $firstRow.psobject.Properties) {
  if ($prop.Value -is [string]) { # Substitute [MySql.Data.Types.MySqlDateTime] here.
    @{
      Name = $prop.Name
      Expression = [scriptblock]::Create("[datetime] `$_.$($prop.Name)")
    }
  }
  else {
    $prop.Name
  }
}

# Now output all rows with the [MySqlDateTime] columns (properties)
# converted to [datetime].
$rows | Select-Object $propArray
  • Related