Отображение специальных значений констант null в DBNull в DataTable

Я работаю с существующей объектной структурой, которая использует специальные значения для представления NULL для примитивов int, DateTime, long. Данные, содержащие эти значения, добавляются в DataTable и отображаются в сторонних элементах управления, таких как XtraGrid.

Все в порядке, за исключением случаев, когда к данным применяются агрегаты. В этом случае, очевидно, обрабатываются специальные значения вместо записей NULL.

Поэтому я думаю, что лучшим решением является сопоставление значений с/из DBNull при вводе в DataRow. Я думал о создании подклассов DataTable и DataRow, но базовые классы не позволяют переопределять методы доступа.

Я мог бы добавить дополнительные функции Get/Set в подклассы, но это зависит от того, чтобы помнить об их использовании. Я мог бы добавить статические вспомогательные функции вместо создания подклассов, но здесь та же проблема.

Есть ли более элегантное решение?

Обновление Агрегирование выполняет сама сетка, поскольку она имеет гибкие элементы управления, позволяющие пользователю определять сводки во время выполнения. Поэтому я думаю, что единственное реальное решение - каким-то образом сопоставить DBNull и/или из него, просто ища элегантный способ сделать это.


person Jon    schedule 15.12.2009    source источник
comment
Как вы читаете данные? Можете ли вы использовать IDataReader для заполнения набора данных?   -  person jmservera    schedule 15.12.2009
comment
Данные поступают из пользовательского вызова сервера и заполняются вручную с помощью AddRow.   -  person Jon    schedule 15.12.2009


Ответы (2)


Вы можете создать метод расширения, который поможет вам заполнить данные и преобразовать значения в dbnull:

public static class DataExtensions
{
    public static DataRow AddRow(this DataRowCollection rowCollection, params object[] values)
    {
        object[] newValues = new object[values.Length];

        for(int i=0;i<values.Length;i++)
        {
            object value = values[i];
            if (value != null)
            {                    
                Type t = value.GetType();
                //check for min value only for value types...
                if (t.IsValueType)
                {
                    //maybe you can do some caching for that...
                    FieldInfo info = t.GetField("MinValue",
                        System.Reflection.BindingFlags.Static
                        | System.Reflection.BindingFlags.Public
                        );
                    if (info != null)
                    {
                        object o = info.GetValue(null);
                        if (value.Equals(o))  //very important == will return false
                        {
                            value = DBNull.Value;
                        }
                    }
                }
            }
            newValues[i] = value;               
        }

        return rowCollection.Add(newValues);
    }
}

И тогда вы сможете написать что-то вроде:

t.Rows.AddRow(a,b,c,d,e);
person jmservera    schedule 16.12.2009
comment
Это подход, который я выбрал — добавление методов расширения GetColumnValue(), SetColumnValue() в DataRow. - person Jon; 16.12.2009

возможно, вы можете создавать условные агрегаты с помощью IIF, например (глупый пример):

        DataTable t= new DataTable();
        t.Columns.Add("id");
        t.Columns.Add("id2");
        t.Columns.Add("id3", typeof(int), "IIF(id="+int.MinValue.ToString()+",id2,id+id2)");
        for (int i = 0; i < 5; i++)
        {
            t.Rows.Add(new object[] { i, 2 * i });
        }

        t.Rows.Add(new object[] { int.MinValue, 2000});

Изменить: адаптировано к вашему комментарию к другому посту.

person jmservera    schedule 15.12.2009
comment
Я думаю, это возможно, но это будет означать удвоение всех столбцов (кроме строк). - person Jon; 15.12.2009
comment
Ну, я не хотел дублировать столбцы, я просто думал, что ваша проблема связана с агрегатами, и мое предложение состояло в том, чтобы изменить агрегатные функции. - person jmservera; 15.12.2009
comment
Хорошо, извините, я вижу, на самом деле это сам элемент управления сеткой, который выполняет агрегацию (поэтому значения обрабатываются неправильно). Добавлю уточнение к вопросу. - person Jon; 15.12.2009