我有一个循环通过从MySqlCommand生成的DataReader,它的查询从某些字段中选择,包括在C#上映射到TINYINT(1)
的2个bool
字段,这就是我所期待的是。
当我将查询更改为使用相同的表格执行UNION ALL
时出现了问题。
在我更改了查询后,我开始收到无效的转换错误。 TINYINT(1)
列现在返回SByte
而不是Boolean
。
这是MySql Server问题吗?一个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???
}
}
在有人问:
之前List<DbDataRecord>
扩展方法将读者“投射”到.Cast<>()
以获取“已被删除的读者”,但它不会以任何方式更改基础数据。答案 0 :(得分:2)
我也可以使用NET Connector 6.3确认问题(?)。
然而,有一个简单的方法可以呼叫reader.GetBoolean()
MySql连接器中的基本IDbDataReader的重写在内部调用读取器字段上的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));
}
因此您可以轻松地将代码调整到这种情况(并且它也适用于查询的单个表版本)
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
bool flag = reader.GetBoolean("tinyint1column");
....
}
}
编辑鉴于您的评论如下,我认为您可以使用DbDataRecord类的扩展方法解决缺少GetBoolean(fieldName)的问题。
我用LinqPad对它进行了测试,它似乎工作正常(如果该字段为空则返回返回的部分)
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);
}
答案 1 :(得分:1)
我不确定这是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;
}
}
}
我无法进行通用转换,因为当union上的两个查询返回行时它会更改类型,所以我写了一些条件来克服这个问题。
请注意,对于MySqlDataReader
,您必须更改扩展方法签名和方法名称:
GetBooleanEx(this MySqlDataReader rec, string fieldName)