2014-04-25 2 views
1

내가 DB에서 데이터를 얻을 다음 코드를 실행해야합니다() OverflowException :SqlDataAdapter.Fill

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) 그들의 값이 범위 등이보다 큰 입력 한 것을 decimal의 형식이 C#인데, 그 이유는 OverflowException입니다.

SQL 쿼리와 DB 구조를 수정하지 않고 C#에서 해당 데이터를 선택할 수있는 방법이 있습니까?

DB 값의 정밀도가 C#보다 높으면 값을 반올림하는 것이 좋습니다. 오버플로가 발생하면 대신 NULL을 보거나 값을 읽을 수없는 다른 표시를보고 싶습니다.

조사 세부 사항 :

문제는 인기처럼 들리 겠지만 나는 마이크로 소프트 같은 문제와 포럼과 거기의 답변에만 one thread을 발견했습니다.

SQL Server Management Studio 2008 자체는 편집 데이터 모드에서 이러한 값을 표시 할 수 없으며 ""를 표시하며 해당 셀을 편집 할 수 없습니다. enter image description here 그러나 SELECT, INSERT 및 UPDATE 명령은 올바르게 작동하고 모든 데이터를 표시합니다.

정밀도가 28 이하인 10 진수 열은 정상적으로 작동하지만 값이 소수점 이하 (38, 38)처럼 오버플로를 일으키지 않더라도 더 정밀도가 높은 열은 실패합니다.이 경우 nvarchar가 삽입시 잘리는 것처럼 잘릴 수 있습니다.

sda.ContinueUpdateOnError = true; 

은 변경되지 않습니다. 나는 이것이 업데이트 작업이 아니라고 생각하기 때문에이 속성은 무시됩니다.

sda.FillError += (sender, args) => 
{ 
    args.Continue = true; 
}; 

예외 던지는을 중지하지만, 데이터가 전혀 반환되지 않습니다 - 단지 하나의 의미 행 내가 내 자신에 대한 해결책을 발견 한 것 같다

CaseName | Decimal_10_2 | Decimal_18_0 | Decimal_18_18 | Decimal_28_0 | Decimal_28_28 | Decimal_38_0 | Decimal_38_20 | Decimal_38_38 | Float | Int 
----------+--------------+--------------+---------------+--------------+---------------+--------------+---------------+---------------+-------+---- 
Null  |    |    |    |    |    |    |    |    |  |  

답변

2

. 그 후, 세포의 DataTable

sda.ReturnProviderSpecificTypes = true; 

맞춤 에러 처리와 닷넷 원시 데이터 유형 추가 전환시킬 수 등 System.Data.SqlTypes.SqlDecimal, System.Data.SqlTypes.SqlString 같은 유형의 값을 포함한다.

그런 다음 PrecisionScale SqlDecimal 값의 속성을 확인하고 필요한 경우 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); 
    } 
} 

UPDATE : 내 구현을 참조하십시오이 문서이기 때문에 AdjustScale 방법에주의하는 것은 정확하지 않다 - digits 매개 변수는 결과 값의 자릿수하지만 자릿수의 변화 아니다 (정확도를 2로 줄이려면 digits=-2을 전달해야 함)

관련 문제