繁体   English   中英

通过 IfxDataReader 读取小数时出现格式错误仅在我的 PC 上发生

[英]Format Error when reading decimals via IfxDataReader occurs only on my PC

我正在尝试使用 IfxDataReader 从 IBM 数据库中获取数据,如下所示:

Using myCon As New IfxConnection("CONSTRING")
    Dim myQuery = "SELECT decimalValue FROM exampletable"
    Using myCmd As New IfxCommand(myQuery, myCon)
        myCon.Open()
        Using myReader As IfxDataReader = myCmd.ExecuteReader
            While myReader.Read
                ' error occurs below
                Dim myVariable As Double = myReader("decimalValue")
            End While
        End Using
    End Using
End Using

我在myReader("decimalValue")收到 System.FormatException。 在调试期间将鼠标悬停在这段代码上,也会显示这个异常,甚至在执行代码行之前。 该异常具有以下堆栈跟踪。

在 System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
在 System.Number.ParseDecimal(字符串值,NumberStyles 选项,NumberFormatInfo numfmt)
在 IBM.Data.Informix.IfxDataReader.GetSytemTypeFromCacheType(类型 systemType,类型 cacheEntryType,对象 cacheEntry)
在 IBM.Data.Informix.IfxDataReader.GetValue(Int32 i)
在 IBM.Data.Informix.IfxDataReader.get_Item(字符串值)

我在我的文件中使用Imports IBM.Data.Informix ,并在我的项目中引用了同名的 DLL。 DLL 的文件版本为4.0.1000.2 ,其产品版本为4.00.01000.2

我发现了这个看起来相似的问题,但是在这里检查提到的框并没有解决问题。 Dim b As Integer = Integer.Parse("1") 导致“System.FormatException:'输入字符串的格式不正确。'”

显然这个问题只发生在我自己的电脑上。 我已经在我的两位同事的计算机以及我们的一台服务器上执行了完全相同的代码,但他们都没有遇到问题。

起初我认为它有事可做,因为我没有安装 Informix Client SDK,因为我在 ibm.com 上发现了一个类似的问题,建议更新 SDK: https ://www.ibm.com/support/pages /apar/IC60254但是在安装了SDK之后它仍然没有工作,我还发现它可以在一个没有安装SDK的同事的PC上工作。 因此,我很困惑,不知道为什么会出现这个问题,为什么只对我来说。

有没有人有线索,可能是什么导致了这个错误?

这里的问题可能有两个:

  1. 价值总是被重视的吗? 可能是 Nothing 或 DbNull?
  2. 您的 PC/机器是否与您的同事使用相同的区域设置/语言?

希望它是这两个问题之一,此代码将有助于解决您的问题。 您必须设置存储数据的正确“默认小数分隔符”以及正确的语言/iso代码来转换/格式化它(在我的SO是意大利语中,意味着存储的数据有“,”作为小数分隔符和语言/iso -代码是“it-IT”)

让我们知道这是否解决了:)

  Private Function ConvertToDecimal(ByVal value As Object) As Decimal

    If value Is DBNull.Value Then Return 0
    If value Is Nothing Then Return 0

    Dim dValue As String = CStr(value)

    'Specify here the default decimal separator and locale that data was stored before
    Dim localeDefaultSeparator As String = ","
    Dim localeDefaultCultureId As String = "it-IT"


    Dim separators As String = System.Text.RegularExpressions.Regex.Replace(dValue, "[0-9]", "")
    Dim decimalseparator As String = ""
    If Not String.IsNullOrEmpty(separators) Then decimalseparator = Char.ToString(separators.Last())

    Dim style As System.Globalization.NumberStyles = System.Globalization.NumberStyles.AllowDecimalPoint Or System.Globalization.NumberStyles.AllowThousands
    Dim provider As System.Globalization.CultureInfo = If(Not String.IsNullOrEmpty(decimalseparator) AndAlso decimalseparator = localeDefaultSeparator, New System.Globalization.CultureInfo(localeDefaultCultureId), System.Globalization.CultureInfo.InvariantCulture)

    Dim retValue As Decimal
    If Decimal.TryParse(dValue, style, provider, retValue) Then Return retValue

    Return 0
  End Function

用法:

Dim myVariable As Double = ConvertToDecimal(myReader("decimalValue"))

扩展 G3nt_M3caj 所说的内容。

某些数据类型(如十进制或日期)的格式取决于您的本地化设置(语言/地区)。 在英语(美国)中,小数点分隔符是“.”。 (千是一个“,”)但在其他语言(和地区)中它们可能会有所不同。 相反,在意大利语或西班牙语中,“,”表示十进制,“。” 为数千人。

.NET 将使用 Windows 中的默认设置,但您可以使用 System.Globalization.CultureInfo 覆盖它。

但是,对于 Informix 客户端(如 .NET 和 ODBC),还有其他设置可以控制客户端如何将数据返回给应用程序。 例如, CLIENT_LOCALE用于指定您希望驱动程序(在本例中为 .NET)将数据返回给应用程序的语言、区域和代码集。

如果您不指定 CLIENT_LOCALE,它将采用默认的“EN_US.1252”(Windows 上为 1252,这因平台而异)这意味着驱动程序将“期望”EN_US 格式的小数(“.”和“,” ) 如果你的 Windows 机器没有使用相同的设置,你会在尝试从数据库中获取小数时出错(这同样适用于日期时间)

看下面的例子:

// ---- dec2.cs ----
// compile with:  csc.exe /R:%INFORMIXDIR%\bin\netf40\IBM.Data.Informix.dll /nologo dec2.cs
//
using System;
using System.IO;
using System.Data;
using System.Text;
using System.Threading;
using IBM.Data.Informix;


class sample {
    static void Main(string[] args) {

     IfxConnection conn;
     try {
        //conn = new IfxConnection("Server=ids1410;Database=sysmaster;CLIENT_LOCALE=en_US.1252");
        conn = new IfxConnection("Server=ids1410;Database=sysmaster;CLIENT_LOCALE=it_IT.1252");
        Console.WriteLine(conn.ConnectionString);
        conn.Open();    
        IfxCommand cmmd = conn.CreateCommand();
        cmmd.CommandText = "SELECT 1.234 from table (set{1}) ";
        Console.WriteLine(cmmd.CommandText);
        IfxDataReader drdr;
        drdr = cmmd.ExecuteReader();
        drdr.Read();
        
        Console.WriteLine("System.Globalization.CultureInfo(\"en-US\")");
        Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
        try {
            Console.WriteLine("\tGetDecimal (en-US):\t"+drdr.GetDecimal(0));          
        }
        catch (Exception e) {
            Console.WriteLine("\t"+e.Message);
            Console.WriteLine("\t"+e.StackTrace);        
        }
        Console.WriteLine("System.Globalization.CultureInfo(\"it-IT\")");
        Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("it-IT");
        try {
            Console.WriteLine("\tGetDecimal (it-IT):\t"+drdr.GetDecimal(0)); 
        }
        catch (Exception e) {
            Console.WriteLine("\t"+e.Message);
            Console.WriteLine("\t"+e.StackTrace);        
        }        
        conn.Close();
     }
     catch (Exception e) {
        Console.WriteLine(e.Message);
        Console.WriteLine(e.StackTrace);
        
     }
   }
}
// ---- dec2.cs ----

如果使用默认的 en_US.1252 运行它,则只有在 CultureInfo 设置为“en-US”时才能执行 GetDecimal(),因为十进制格式必须匹配(客户端返回的用途和 .net 期望的内容)。

d:\Infx\work\cs>dec2
Server=ids1410;Database=sysmaster;CLIENT_LOCALE=en_US.1252
SELECT 1.234 from systables
System.Globalization.CultureInfo("en-US")
        GetDecimal (en-US):     1.234
System.Globalization.CultureInfo("it-IT")
        Input string was not in a correct format.
           at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt)
   at IBM.Data.Informix.IfxDataReader.GetDecimal(Int32 i)
   at sample.Main(String[] args)

d:\Infx\work\cs>

如果您将设置更改为“it-IT”(意大利语/意大利),它将失败,您在原始帖子中提到的例外情况。 因为他们不会匹配。 .NET 需要一个“1,234”,但它得到一个“1.234”

如果您更改连接字符串中的 CLIENT_LOCALE 值,则相反:

d:\Infx\work\cs>dec2
Server=ids1410;Database=sysmaster;CLIENT_LOCALE=it_IT.1252
SELECT 1.234 from systables
System.Globalization.CultureInfo("en-US")
        Input string was not in a correct format.
           at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt)
   at IBM.Data.Informix.IfxDataReader.GetDecimal(Int32 i)
   at sample.Main(String[] args)
System.Globalization.CultureInfo("it-IT")
        GetDecimal (it-IT):     1,234

d:\Infx\work\cs>

链接讨论了这一点(与 .NET 相关),但它可能会变得更复杂一些,因为还有其他 Informix 设置可以改变它,比如 DBMONEY。 DBMONEY 可用于指定十进制格式,而无需指定 CLIENT_LOCALE(因此不会影响代码集顺序等其他内容)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM