2012-07-31 17 views
0

我正在研究需要使用「類似」模式連接到不同數據庫類型(SQL Server,Oracle,DB2)的應用程序。我說「類似」模式的表名,列等是相同的,但底層數據類型是特定於該數據庫類型的。例如,在SQL Server和Oracle數據庫中,我都有一個名爲'tablename'的表和一個名爲'column'的列。 'column'的數據類型對於Oracle是NUMBER,對於SQL Server是float。C#IDataReader跨數據庫的通用訪問器

我很好,通過通用的ADO接口獲取相應的提供程序工廠,連接和查詢,我不知道和有問題是我應該如何訪問此列。對於Oracle,我相信我應該爲NUMBER數據類型字段使用訪問函數'GetDecimal()',事實上,似乎使用任何其他訪問方法,比如GetInt32(),GetDouble(),我會得到一個類型轉換例外。對於SQL Server,我應該使用訪問函數'GetDouble()'。有沒有一種方法/策略可以使用單個訪問器函數來獲取此值,而不考慮底層數據庫數據類型?請注意,我無法控制後端數據庫架構。

謝謝,我欣賞這些回覆。

+0

只是我的兩分錢,我知道你說你沒有訪問底層的數據庫模式,但我仍然爭辯說,這真的是你應該開始的地方。禁止更改模式我沒有看到避免使用條件的方法(基於您連接的數據庫)來解決這樣的問題。 – 2012-07-31 02:22:48

+1

我會建議爲每個數據庫使用不同的接口。這將確保您不會太緊密耦合,並具有未來架構更改的靈活性。 – NoviceProgrammer 2012-07-31 05:53:15

回答

0

您可以使用IDataReader.GetValue,但您仍然需要在該行的某個位置投射。您可以將訪問抽象爲通用包裝,並在數據讀取器上使用GetSchemaTable作爲機制,以便根據什麼將GetValue的結果轉換爲明智決策。

0

是的,你可以。考慮到您可以將兩種類型(SqlServer的float和Oracel的數量)都轉換爲像decimal這樣的.NET數據類型,您可以依賴System.Convert類中的方法。你應該這樣做:

internal static decimal Read(IDbCommand cmd) 
{ 
    cmd.CommandText = @"SELECT column FROM tablename LIMIT 1"; 
    using (var r = cmd.ExecuteReader()) 
    { 
     while(r.Read()) 
     { 
      return Convert.ToDecimal(r[0]); 
      //instead of return r.GetDecimal(0); 

      //or even better return r[0].ToFormattedDecimal(); 
     } 
    } 
} 

public static decimal ToFormattedDecimal(this object d) 
{ 
    if (d is DBNull || d == null) //important line - to check DbNull 
     return 0; //your value 

    try 
    { 
     return Convert.ToDecimal(d).Normalize(); 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
     // or may be return 0; 
    } 
} 

public static decimal Normalize(this decimal d) 
{ 
    return d/1.00000000000000000000000000000m; 
} 

我寫了一個擴展方法,使您的工作更輕鬆。 Normalize功能修剪所有不需要的零在最後的十進制值,如23.0000等