Question

I'm still very new to C# so please bear with me. I have an Access database with a table that looks like this:

ID1  ID2     Name
----------------------
1111 1234567 Joe
2222 1234567 Patricia
3333 7654321 Laurie

None of the fields contain null values. I'm trying to store the length of the longest text representation of the values of each column in a DataTable.

Based on rein's answer to this similar question, I included this handy generic function:

public static T ConvertFromDBVal<T>(object obj)
{
    if (obj == null || Convert.IsDBNull(obj))
        return default(T);
    else
        return (T)obj;
}

I get the data from the table as follows:

public DataTable GetMetadata(string tableName)
{
    ...

    // My OLEDB connection _oleConnection is already open

    OleDbCommand selectTable = new OleDbCommand("SELECT * FROM [" +
        tableName + "]", _oleConnection);

    OleDbDataReader oleReader = selectTable.ExecuteReader();

    DataTable schemaTable = oleReader.GetSchemaTable().Copy();
    schemaTable.Columns.Add("_maxCharLength", typeof(int));

    foreach (DataRow schemaRow in schemaTable.Rows)
    {
        OleDbCommand getMax = new OleDbCommand();
        getMax.Connection = _oleConnection;

        // Convert non-text fields to strings before getting lengths

        if (schemaRow.Field<Type>("DataType") == typeof(string))
        {
            getMax.CommandText = "SELECT MAX(LEN(" +
                schemaRow.Field<string>("ColumnName") + ")) FROM " +
                tableName;
        }
        else
        {
            getMax.CommandText = "SELECT MAX(LEN(STR(" +
                schemaRow.Field<string>("ColumnName") + "))) FROM " +
                tableName;
        }

        int maxCharLength = ConvertFromDBVal<int>(getMax.ExecuteScalar());

        schemaRow.SetField(schemaRow.Field<int>("_maxCharLength"),
            maxCharLength);

        getMax.Dispose();
        getMax = null;
    }

    ...

    return schemaTable;
}

The debugger gets mad at schemaRow.SetField(...) and says:

Cannot cast DBNull.Value to type 'System.Int32'. Please use a nullable type.

So I tried using a nullable type. I replaced

schemaTable.Columns.Add("_maxCharLength", typeof(int?));   // was typeof(int)

Then the debugger says

DataSet does not support System.Nullable<>.

So I changed it back to int. Even though I used the function to convert any null values, I checked the values and their types in the foreach loop as follows:

Console.WriteLine("{0}, {1}, {2}, {3}",
    tableName,
    schemaRow.Field<string>("ColumnName"),
    maxCharLength,
    maxCharLength.GetType());

This works with no problem at all. I get the following in the console:

Table1, ID1, 4, System.Int32
Table1, ID2, 7, System.Int32
Table1, Name, 8, System.Int32

No null values, no exceptions, everything is as I expect it to be. Then why won't SetField let me put those values in the DataTable?

Was it helpful?

Solution

I think you need to change the line for SetField to

 schemaRow.SetField("_maxCharLength", maxCharLength);

The DataRow.SetField extension requires for its first parameter the name of the column, or the ordinal position of the column inside the columns collection or a DataColumn instance.

The error message is caused by the fact that you try to read the value of the _maxCharLength field using the DataRow.Field<T> extension. But at that point of your code the _maxCharLength field is still null because you have not yet set any value for it.

The compiler cannot warn you about this error because from a logical point of view you are calling a valid overload of the SetField extension. The one that requires an integer to express the ordinal position of the column to set value for.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top