简体   繁体   中英

C# IDataReader generic accessors across databases

I'm working on an application that will need to connect to different database types (SQL Server, Oracle, DB2) with 'similar' schemas. I say 'similar' schemas in that the table names, columns etc... are the same, but the underlying data types are specific to that database type. For example, in both SQL Server and Oracle databases I have a table named 'tablename' and a column named 'column'. The data type of 'column' is NUMBER for Oracle and float for SQL Server.

I'm fine with getting the appropriate provider factory, connecting, and querying via generic ADO interfaces, what I'm not sure about and am having problems with is how I should access this column.

For Oracle, I believe I am supposed to use the accessor function 'GetDecimal()' for a NUMBER datatype field, in fact it seems that using any other accessor such as GetInt32(), GetDouble() I get a cast exception. For SQL Server I am supposed to use the accessor function 'GetDouble()'. Is there a way/strategy to get this value with a single accessor function regardless of the underlying database data type? Note, I have no control over the backend database schema.

Thanks, I appreciate the responses.

You could use IDataReader.GetValue but you would still need to cast somewhere down the line. You could abstract the access away into a generic wrapper and use GetSchemaTable on the data reader as the mechanism to make informed decisions on what to cast the result of GetValue to.

Yes you can. Considering you can cast both types (float of SqlServer and number of Oracel) to a .NET data type like decimal, you can rely on the methods in System.Convert class. You should actually do:

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;
}

I wrote an extension method to make your job easier. The Normalize function trims all unwanted zeroes at the end for decimal values like 23.0000 etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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