문제

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