如果使用 UNION ALL,MySqlDataReader returns 同一列的不同类型
MySqlDataReader returns different type for same column if UNION ALL is used
我有一个循环遍历从 MySql 命令生成的 DataReader,它的查询从一些字段中选择,包括 2 个 TINYINT(1)
字段映射到 C# 上的 bool
s 和这个正是我所期待的。
当我将查询更改为使用相同的 table 执行 UNION ALL
时出现了问题。
更改查询后,我开始收到无效转换错误。 TINYINT(1)
列现在 return SByte
而不是 Boolean
.
这是 MySql 服务器问题吗? MySql Net/Connector 问题?这是预期的行为吗?
示例查询:
string sql = @"SELECT tinyint1column FROM mytable WHERE id = 1";
command.CommandText = sql;
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = (bool)reader["tinyint1column"]; // OK - No error
}
}
sql = @"SELECT tinyint1column FROM mytable WHERE id = 1
UNION ALL
SELECT tinyint1column FROM mytable WHERE id = 2";
command.CommandText = sql;
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = (bool)reader["tinyint1column"]; // Invalid cast error???
}
}
之前有人问:
- 我在共享主机上安装了 MySql Server 5.1,所以我无法升级服务器。
- 我正在使用 MySql.Data 版本 6.5.4,因为它是我唯一可以在具有 medium/partial 推力的共享主机上编译为 运行 的版本。
- 我其实是"casting"把reader改成了
List<DbDataRecord>
用.Cast<>()
扩展方法得到了"disconected reader",但是没有变任何方式的基础数据。
我也可以通过 NET Connector 6.3 确认问题(?)。
然而,调用 reader.GetBoolean()
.
有一个简单的方法
MySql 连接器中基础 IDbDataReader 的覆盖在 reader 字段
内部调用 Convert.ToBoolean()
public bool GetBoolean(string name)
{
return this.GetBoolean(this.GetOrdinal(name));
}
public override bool GetBoolean(int i)
{
return Convert.ToBoolean(this.GetValue(i));
}
因此您可以轻松调整代码以适应这种情况(它也适用于单个 table 版本的查询)
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = reader.GetBoolean("tinyint1column");
....
}
}
编辑 鉴于您在下面的评论,我认为您可以使用 DbDataRecord class 的扩展方法解决缺少 GetBoolean(fieldName) 的问题。
我已经用 LinqPad 对此进行了测试,它似乎可以正常工作(如果该字段为空,则 return 的一部分)
public bool GetBoolean(DbDataRecord rec, string fieldName)
{
int pos = rec.GetOrdinal(fieldName);
if(rec.IsDBNull(pos))
return false; // ??
object result = rec.GetValue(pos);
return Convert.ToBoolean(result);
}
我不确定这是 MySql 问题还是连接器问题,但这是个问题。
从@Steve 的回答中得到一些启发后,我想出了一个解决方案:
public static class DbDataRecordExtensions
{
public static bool GetBoolean(this DbDataRecord rec, string fieldName)
{
var index = rec.GetOrdinal(fieldName);
var value = rec.GetValue(index);
if (value is bool || value is Boolean)
{
return (bool)value;
}
else if (value is SByte || value is sbyte)
{
return (sbyte)value != 0;
}
else
{
return rec.GetInt64(index) != 0;
}
}
}
我无法进行通用转换,因为当两个查询联合 return 行时它会更改类型,所以我写了一些条件来克服这个问题。
请注意,对于 MySqlDataReader
,您必须更改扩展方法签名和方法名称:
GetBooleanEx(this MySqlDataReader rec, string fieldName)
我有一个循环遍历从 MySql 命令生成的 DataReader,它的查询从一些字段中选择,包括 2 个 TINYINT(1)
字段映射到 C# 上的 bool
s 和这个正是我所期待的。
当我将查询更改为使用相同的 table 执行 UNION ALL
时出现了问题。
更改查询后,我开始收到无效转换错误。 TINYINT(1)
列现在 return SByte
而不是 Boolean
.
这是 MySql 服务器问题吗? MySql Net/Connector 问题?这是预期的行为吗?
示例查询:
string sql = @"SELECT tinyint1column FROM mytable WHERE id = 1";
command.CommandText = sql;
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = (bool)reader["tinyint1column"]; // OK - No error
}
}
sql = @"SELECT tinyint1column FROM mytable WHERE id = 1
UNION ALL
SELECT tinyint1column FROM mytable WHERE id = 2";
command.CommandText = sql;
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = (bool)reader["tinyint1column"]; // Invalid cast error???
}
}
之前有人问:
- 我在共享主机上安装了 MySql Server 5.1,所以我无法升级服务器。
- 我正在使用 MySql.Data 版本 6.5.4,因为它是我唯一可以在具有 medium/partial 推力的共享主机上编译为 运行 的版本。
- 我其实是"casting"把reader改成了
List<DbDataRecord>
用.Cast<>()
扩展方法得到了"disconected reader",但是没有变任何方式的基础数据。
我也可以通过 NET Connector 6.3 确认问题(?)。
然而,调用 reader.GetBoolean()
.
有一个简单的方法
MySql 连接器中基础 IDbDataReader 的覆盖在 reader 字段
public bool GetBoolean(string name)
{
return this.GetBoolean(this.GetOrdinal(name));
}
public override bool GetBoolean(int i)
{
return Convert.ToBoolean(this.GetValue(i));
}
因此您可以轻松调整代码以适应这种情况(它也适用于单个 table 版本的查询)
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = reader.GetBoolean("tinyint1column");
....
}
}
编辑 鉴于您在下面的评论,我认为您可以使用 DbDataRecord class 的扩展方法解决缺少 GetBoolean(fieldName) 的问题。
我已经用 LinqPad 对此进行了测试,它似乎可以正常工作(如果该字段为空,则 return 的一部分)
public bool GetBoolean(DbDataRecord rec, string fieldName)
{
int pos = rec.GetOrdinal(fieldName);
if(rec.IsDBNull(pos))
return false; // ??
object result = rec.GetValue(pos);
return Convert.ToBoolean(result);
}
我不确定这是 MySql 问题还是连接器问题,但这是个问题。
从@Steve 的回答中得到一些启发后,我想出了一个解决方案:
public static class DbDataRecordExtensions
{
public static bool GetBoolean(this DbDataRecord rec, string fieldName)
{
var index = rec.GetOrdinal(fieldName);
var value = rec.GetValue(index);
if (value is bool || value is Boolean)
{
return (bool)value;
}
else if (value is SByte || value is sbyte)
{
return (sbyte)value != 0;
}
else
{
return rec.GetInt64(index) != 0;
}
}
}
我无法进行通用转换,因为当两个查询联合 return 行时它会更改类型,所以我写了一些条件来克服这个问题。
请注意,对于 MySqlDataReader
,您必须更改扩展方法签名和方法名称:
GetBooleanEx(this MySqlDataReader rec, string fieldName)