質問

I am using the c# Dynamic Linq library for writing custom queries against a data table. The problem I am having is that when I'm trying to perform summary operations on fields that have nulls I am getting errors.

I'm trying to execute a query similar to:

 var query = myDataTable.AsEnumerable().AsQueryable();

 var newquery = query.GroupBy("new (get_item(@0).ToString() AS Forename)", "it", groupList.ToArray());

 newquery = newquery.Select("new (it.Key.Tier.ToString() as Tier, @0(it) as SumTotal", funcs.ToArray());

If there column I am summing by has Null values then I get an error "Cannot cast DBNull.Value to type 'System.Double'. Please use a nullable type."

The funcs array contains a lambda expression to execute the Sum function. It is built by calling the below function.

public LambdaExpression GetGroupByLambdaExpression(Type groupByKeyType, string columnName, Type columnType, string expType)
    {
        ConstantExpression colParam = Expression.Constant(columnName, typeof(string));

        MethodInfo fieldMethod = typeof(DataRowExtensions).GetMethod("Field", new Type[] {typeof(DataRow), typeof(string)});
        fieldMethod = fieldMethod.MakeGenericMethod(columnType);
        ParameterExpression rowParam = Expression.Parameter(typeof(DataRow), "r");

        MethodCallExpression fieldMethodCall = Expression.Call(fieldMethod, rowParam, colParam);
        dynamic columnExpression = Expression.Lambda(fieldMethodCall, rowParam);

        MethodInfo sumMethod = null;
        if (expType == "Count")
        {
            //Count will return 2 methods, we only want the first one with 1 parameter
            sumMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == expType & m.ReturnType.Equals(columnType) & m.IsGenericMethod & m.GetParameters().Count() == 1);
        }
        else if (expType == "Average")
        {
            //Average has multiple overrides so just use the first one                
            if (columnType == typeof(Int16) || columnType == typeof(Int32) || columnType == typeof(Int64))
            {
                sumMethod = typeof(Enumerable).GetMethods().First(m => m.Name == expType & m.ReturnType.Equals(typeof(double)) & m.IsGenericMethod);
            }
            else
            {
                sumMethod = typeof(Enumerable).GetMethods().First(m => m.Name == expType & m.ReturnType.Equals(columnType) & m.IsGenericMethod);
            }
        }
        else
        {
            sumMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == expType & m.ReturnType.Equals(columnType) & m.IsGenericMethod);
        }

        sumMethod = sumMethod.MakeGenericMethod(typeof(DataRow));

        ParameterExpression groupParam = Expression.Parameter(groupByKeyType, "g");

        MethodCallExpression sumMethodCall = null;
        if (expType == "Count")
        {
            sumMethodCall = Expression.Call(sumMethod, groupParam);
        }
        else
        {
            sumMethodCall = Expression.Call(sumMethod, groupParam, columnExpression);            
        }

        dynamic sumALambda = Expression.Lambda(sumMethodCall, groupParam);

        return sumALambda;
    }

Has anybody any ideas how to handle the DbNull values on the datatable? I'm totally stumped

役に立ちましたか?

解決 2

Actually the answer was to replace the DataTable column data types with their nullable equivalents in the building of the lambda expression.

他のヒント

Is there any reason you can't just filter the data table before you start querying it?

var query = myDataTable.Where(val => !Convert.IsDbNull(val)).AsEnumerable().AsQueryable();
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top