我需要从DB获取数据并执行以下代码:
using (var dataRetrievingCommand = new SqlCommand(selectQuery, connection))
{
var dataTable = new DataTable("DataTable");
var sda = new SqlDataAdapter(dataRetrievingCommand);
sda.Fill(dataTable); //OverflowException here
return dataTable;
}
问题是数据库中的某些列的类型为decimal(38,10)
,decimal(38, 0)
等。它们的值范围大于C#中decimal
的类型,这就是我得到{{{ 1}}。
在没有修改SQL查询和数据库结构的情况下,有没有办法在C#中选择数据?
如果DB值精度高于C#,则可以对值进行舍入。如果发生溢出,我希望看到NULL,或者任何其他标记该值无法读取。
调查详情:
这个问题听起来很受欢迎,但我在微软论坛上发现只有one thread同样的问题而没有答案。
SQL Server Management Studio 2008本身无法在编辑数据模式下显示此类值 - 它显示“”并且不允许编辑这些单元格。 但SELECT,INSERT和UPDATE命令工作正常并显示所有数据。
精度为28或更小的十进制列工作正常,但任何更高精度的列都会失败,即使值不会导致像decimal(38,38)那样的溢出,只需修剪就像在插入时修剪nvarchar一样。
OverflowException
不会改变任何事情。我认为这不是更新操作,因此忽略此属性。
sda.ContinueUpdateOnError = true;
停止异常抛出,但根本没有返回任何数据 - 只是单个无意义的行
sda.FillError += (sender, args) =>
{
args.Continue = true;
};
答案 0 :(得分:2)
我似乎已经找到了自己的解决方案。
sda.ReturnProviderSpecificTypes = true;
之后,DataTable单元格包含System.Data.SqlTypes.SqlDecimal
,System.Data.SqlTypes.SqlString
等类型的值,可以通过自定义错误处理进一步转换为本机.NET数据类型。
然后我检查SqlDecimal值的Precision
和Scale
属性,如果需要,使用SqlDecimal.AdjustScale()方法对值进行舍入。可以通过Value
属性访问结果。看我的实施:
public struct DecimalEx
{
private decimal m_Value;
public decimal Value
{
get { return m_Value; }
}
private bool m_IsNull;
public bool IsNull
{
get { return m_IsNull; }
}
private bool m_IsOverflow;
public bool IsOverflow
{
get { return m_IsOverflow; }
}
private bool m_IsRounded;
public bool IsRounded
{
get { return m_IsRounded; }
}
private bool m_IsPositive;
public bool IsPositive
{
get { return m_IsPositive; }
}
public DecimalEx(decimal value)
{
m_Value = value;
m_IsNull = false;
m_IsOverflow = false;
m_IsRounded = false;
m_IsPositive = value >= 0;
}
public static explicit operator DecimalEx(SqlDecimal dbValue)
{
var result = new DecimalEx();
if (dbValue.IsNull)
{
result.m_Value = 0;
result.m_IsNull = true;
result.m_IsOverflow = false;
result.m_IsRounded = false;
result.m_IsPositive = false;
return result;
}
else
{
result.m_IsNull = false;
result.m_IsPositive = dbValue.IsPositive;
}
if (dbValue.Precision > 28)
{
result.m_IsRounded = true;
if (dbValue.Precision - dbValue.Scale <= 28)
{
var adjustedValue = SqlDecimal.AdjustScale(dbValue, 28 - dbValue.Precision, true);
result.m_Value = adjustedValue.Value;
result.m_IsOverflow = false;
}
else
{
result.m_Value = 0;
result.m_IsOverflow = true;
}
}
else
{
result.m_Value = dbValue.Value;
result.m_IsRounded = false;
}
return result;
}
public override string ToString()
{
return ToString(CultureInfo.CurrentCulture);
}
public string ToString(IFormatProvider provider)
{
if (IsNull)
{
return string.Empty;
}
if (IsOverflow)
{
return "###";
}
return Value.ToString(provider);
}
}
更新:要小心使用AdjustScale方法,因为它的文档不准确 - digits
参数不是结果值中的位数,而是数量的变化数字(所以要将精度降低2,你必须通过digits=-2
)