为什么不能 MySQL Connector.NET 正确地将类型映射到 C# 类型?

Why cannot MySQL Connector.NET correctly map types to C# types?

MySQL table 定义:

CREATE TABLE `table` (
  `id` tinyint(1) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Auto-increment ID',
  `data_provider_id` tinyint(1) unsigned NOT NULL COMMENT 'Data provider ID',
  `is_active` bit(1) NOT NULL DEFAULT b'1' COMMENT '0 = retired source',
  PRIMARY KEY (`id`),
  KEY `DATA_PROVIDER_ID` (`data_provider_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8

C#代码:

public static class MySqlConnector
{
    public static DataTable QueryDatabase(
            MySqlConnection mysqlConnection,
            string mysqlQuery)
    {
        MySqlCommand mysqlCommand = new MySqlCommand(mysqlQuery, mysqlConnection);
        MySqlDataReader mysqlDataReader = mysqlCommand.ExecuteReader();

        DataTable dataTable = new DataTable();
        dataTable.Load(mysqlDataReader);

        return dataTable;
    }
}

...

mysqlQuery = @"
    SELECT
      `id`,
      `data_provider_id`,
      `is_active`
    FROM
      `{0}`;
    ";
mysqlQuery = String.Format(mysqlQuery, tableName);
DataTable dt = MySqlConnector.QueryDatabase(mysqlConnection, mysqlQuery);

现在当我在 dt 字段上调用 ​​GetType() 时,它说 idInt32(而不是 Byte),data_provider_idByte(令人惊讶的正确),is_activeUint64(而不是 Boolean)。

情况变得更糟。我有另一个 table,其中 id 字段是 int(1) unsigned 并且 QueryDatabase() 仍然 returns 它作为一个有符号整数。


用于快速测试的 PowerShell 代码:

# Importing MySQL Connector.NET DLL.
$sMySqlServer = "server"
$sPath = "\{0}\Connector.NET 6.9.7\Assemblies\v4.5\MySql.Data.dll" `
    -f $sMySqlServer
Add-Type -Path $sPath

# Creating MySQL connection.
$sMySqlUser = "user"
$sMySqlPassword = "password"
$sMySqlDatabase = "test"

$sMySqlConnectionString = "server={0};uid={1};pwd={2};database={3};" `
    -f $sMySqlServer, $sMySqlUser, $sMySqlPassword, $sMySqlDatabase
$oMySqlConnection = New-Object -TypeName MySql.Data.MySqlClient.MySqlConnection
$oMySqlConnection.ConnectionString = $sMySqlConnectionString
$oMySqlConnection.Open()

# Getting raw data.
$sMySqlQuery = "SELECT * FROM `table` ;"
$oMySqlCommand = New-Object -TypeName `
    MySql.Data.MySqlClient.MySqlCommand($sMySqlQuery, $oMySqlConnection)
$oMySqlDataReader = $oMySqlCommand.ExecuteReader()
$oDataTable = New-Object -TypeName System.Data.DataTable
$oDataTable.Load($oMySqlDataReader)

$oDataTable | Get-Member

输出:

   TypeName: System.Data.DataRow

Name              MemberType            Definition                                        
----              ----------            ----------                                        
AcceptChanges     Method                void AcceptChanges()                              
BeginEdit         Method                void BeginEdit()                                  
CancelEdit        Method                void CancelEdit()                                 
ClearErrors       Method                void ClearErrors()                                
Delete            Method                void Delete()                                     
EndEdit           Method                void EndEdit()                                    
Equals            Method                bool Equals(System.Object obj)                    
GetChildRows      Method                System.Data.DataRow[] GetChildRows(string relat...
GetColumnError    Method                string GetColumnError(int columnIndex), string ...
GetColumnsInError Method                System.Data.DataColumn[] GetColumnsInError()      
GetHashCode       Method                int GetHashCode()                                 
GetParentRow      Method                System.Data.DataRow GetParentRow(string relatio...
GetParentRows     Method                System.Data.DataRow[] GetParentRows(string rela...
GetType           Method                type GetType()                                    
HasVersion        Method                bool HasVersion(System.Data.DataRowVersion vers...
IsNull            Method                bool IsNull(int columnIndex), bool IsNull(strin...
RejectChanges     Method                void RejectChanges()                              
SetAdded          Method                void SetAdded()                                   
SetColumnError    Method                void SetColumnError(int columnIndex, string err...
SetModified       Method                void SetModified()                                
SetParentRow      Method                void SetParentRow(System.Data.DataRow parentRow...
ToString          Method                string ToString()                                 
Item              ParameterizedProperty System.Object Item(int columnIndex) {get;set;},...
data_provider_id  Property              byte data_provider_id {get;set;}                  
id                Property              int id {get;set;}                                 
is_active         Property              uint64 is_active {get;set;}                       

SSDD


[已解决] 尽管 wchiquito 的回答不是一个完整的解决方案,但它把我推向了正确的方向。 DataTable.Load() 中的类型转换确实有些损坏,因此您需要在调用 Load() 之前向 DataTable 添加基本架构。以下可能并不完美,但对我有用:

private static void TranslateSchema(
        DataTable dataTable,
        MySqlDataReader mysqlDataReader)
{
    string columnName;
    Type columnType;

    mysqlDataReader.Read();

    for (int i = 0; i < mysqlDataReader.FieldCount; i++)
    {
        columnName = mysqlDataReader.GetName(i);
        columnType = mysqlDataReader.GetFieldType(i);

        dataTable.Columns.Add(columnName, columnType);
    }
}

bit(1) 仍然变成 UInt64 但我可以接受。

Connector/Net 使用的是什么版本?使用 6.9.7 版本我无法重现该问题。

MySQL:

CREATE TABLE `table` (
    `id` TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Auto-increment ID',
    `data_provider_id` TINYINT(1) UNSIGNED NOT NULL COMMENT 'Data provider ID',
    `is_active` BIT(1) NOT NULL DEFAULT b'1' COMMENT '0 = retired source',
    `id_temp` INT(1) UNSIGNED DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `DATA_PROVIDER_ID` (`data_provider_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

C#:

...
DataTable schema = dr.GetSchemaTable();
...

结果:

`id`               -> System.Byte
`data_provider_id` -> System.Byte
`is_active`        -> System.UInt64
`id_temp`          -> System.UInt32

6.2.3.1 Collections

...
DataTable table = mysqlConnection.GetSchema("DataTypes");
...

结果:

TypeName = BIT
...
CreateFormat = BIT
... 
DataType = System.UInt64
...
============================
TypeName = TINY INT
...
CreateFormat = TINYINT UNSIGNED
...
DataType = System.Byte
...
============================
TypeName = INT
...
CreateFormat = INT UNSIGNED
...
DataType = System.UInt32
...