Click here to Skip to main content
15,887,585 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
See more:
Day 3 trying to solve this.

I'm trying to set a variable in C# equal to the values I retrieve from the database, as I have done hundreds of times. I have literally no idea what I'm doing wrong.

My problem is with DBToType<t> while iterating DataTable.Rows to get a field from it's ItemArray.

for ( int i = 0 ; i < dt.Rows.Count - 1 ; i++ ) //Looping through rows
{
	long COLUMN_PROPID = DBToType<long>( dt.Rows[i].ItemArray[5] ); 
}


DBToType produces "Unable to convert from type object to type long"


/// <summary>
		/// Converts DB types to C# Types and ensures that DBNull gets converted to the default value for the type.
		/// </summary>
		/// <typeparam name="T">The expected return type</typeparam>
		/// <param name="value">The value of a column, straight form the database provider</param>
		/// <returns>The value as its coorisponding C# Type, with DBNull converted to the default value of the type. </returns>
		public T DBToType<T> ( T value )
		{
			if ( !Convert.IsDBNull ( value ) )
			{
				return ( T ) Convert.ChangeType ( value , typeof ( T ) );
			}
			else
			{
				return default ( T );   //returns the default for the type... not null
			}
		}


What I have tried:

Everything under the sun...

This was my first attempt at solving this with a generic method.
Posted
Updated 26-Dec-17 14:55pm

1 solution

To exclude the possibility that you are getting an object that can't be converted to a long, test with another function that uses Int64.TryGetValue, and break on error to examine the data.

I would rather use hard-coded Type specific conversion methods, which throw useful errors. Use of 'ChangeType is expensive. Here's an example of the type of Extension method I use:
public static class ConversionExtensions
{
    public static Int32 ToInt(this string str, bool doThrowOnError = true, int defaultValue = Int32.MinValue)
    {
        int i;

        if (Int32.TryParse(str, out i))
        {
            return i;
        }

        if (doThrowOnError)
        {
            throw new ArgumentException($"{str} is not convertible to Int32");
        }

        return defaultValue;
    }
}
If you want to "go generic," then try something like this:
using System.ComponentModel; // required

// written quickly: not fully tested
public T2 DbTypeConverter<T1,T2>(T1 value)
{
    if (value == null || Convert.IsDBNull(value))
    {
        return default(T2);
    }

    TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(T2));

    if (typeConverter.CanConvertFrom(typeof(T1)))
    {
        try
        {
            return (T2) Convert.ChangeType(value, typeof(T2));
        }
        catch (Exception ex)
        {
            switch (ex.GetType().Name)
            {
                // fill these in with meaningful actions !
                case "InvalidFormatException":
                    break;
                case "InvalidCastException":
                    break;
                case "FormatException":
                    break;
                case "OverflowException":
                    break;
                case "ArgumentException":
                    break;
            }
        }
    }

    return default(T2); //returns the default for the type... not null
}

// simple tests
    // long lng1 = DbTypeConverter<string, long>("57657777");
    
    // long lng2 = DbTypeConverter<string, long>("34.45");
    
    // long lng3 = DbTypeConverter<string, long>(DateTime.Now.ToString());
Good info on what you can, and can't, do with TypeConverter: [^]
 
Share this answer
 
v3
Comments
[no name] 27-Dec-17 14:22pm    
Hi Bill, I was only wanting to go generic because I thought it seemed common practice these days to avoid multiple methods that do the same thing, but for different data types. I was not sure why I am not getting useful error messages until you mentioned it, though, so I think I'll be better off doing that. Still, this is day 4 on trying to fix this, so whatever works is what I'll implement today and improve it later. I appreciate your feedback and will accept your answer later.
BillWoodruff 28-Dec-17 1:45am    
Glad you got some ideas from this Rick; it was "educational" for me to re-visit the issue. While generics are a profoundly useful tool, in situations where you are sure you are dealing with a discrete set of Types, you get more performance, imho, and more maintainable code, by hard-coding per type methods.

Given a relational database with a schema of fixed Types, I'd assume a non-generic Type conversion strategy would be more appropriate ... your mileage may vary.

cheers, Bill
[no name] 28-Dec-17 4:29am    
Ultimately, I opted to go the strongly typed route instead. Basically, I just duplicated all of the OleDbDataReader GetType methods, like GetInt32(x), etc, such that they are now available to me without needing the open datareader, which I've read requires an exclusive lock on the database. Generics have been around for years, but since I was a classic asp developer back in the ice ages, I'm struggling to get up to date with that and much more. Thanks for your help!
BillWoodruff 28-Dec-17 4:48am    
You're welcome, Rick. I've appended an example of the extension methods I use to the answer above.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900