none
Dynamic LINQ expression for OfType and Sum RRS feed

  • Question

  • Hello, I'm currently using Dynamic LINQ API in my applications. In a point, I need to have dynamic LINQ equivalent of OfType and Sum method, but unable to find the correct way to create the expression tree. Can anyone help? Current code: db.Orders.OfType<Order>.Sum( o => o.TotalAmount ); Desired code: db.Orders.OfType("northWindModel.Order").Sum("TotalAmount"); Thanks, James.
    Thursday, January 21, 2010 2:42 AM

Answers

  • Hello James,

     

    Welcome to LINQ to SQL forum!

     

    Are you using this Dynamic LINQ Library?  If so, you can refer to the following sample codes to make the dynamic version of OfType() and Sum() methods.  I will explain them later. 

    ======================================================================================================

        public static class MyQueryExtensions

        {

            public static IQueryable OfType(this IQueryable source, string typeStr)

            {

                if (source == null)

                {

                    throw new ArgumentNullException("source");

                }

                if (typeStr == null)

                {

                    throw new ArgumentNullException("typeStr");

                }

     

                Type type = Assembly.GetExecutingAssembly().GetType(typeStr);

                MethodInfo methodOfType = typeof(Queryable).GetMethods().First(m => m.Name == "OfType" && m.IsGenericMethod);

     

                return source.Provider.CreateQuery(Expression.Call(null, methodOfType.MakeGenericMethod(new Type[] { type }), new Expression[] { source.Expression }));

            }

     

            public static object Sum(this IQueryable source, string member)

            {

                if (source == null)

                {

                    throw new ArgumentNullException("source");

                }

                if (member == null)

                {

                    throw new ArgumentNullException("member");

                }

     

                PropertyInfo prop = source.ElementType.GetProperty(member);

                ParameterExpression param = Expression.Parameter(source.ElementType, "s");

                Expression selector = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);

                MethodInfo sumMethod = typeof(Queryable).GetMethods().First(m => m.Name == "Sum" && m.ReturnType == prop.PropertyType && m.IsGenericMethod);

                return source.Provider.Execute(Expression.Call(null, sumMethod.MakeGenericMethod(new Type[] { source.ElementType }), new Expression[] { source.Expression, Expression.Quote(selector) }));

            }

     

            public static object Sum<TSource>(this IQueryable<TSource> source, string member)

            {

                if (source == null)

                {

                    throw new ArgumentNullException("source");

                }

                if (member == null)

                {

                    throw new ArgumentNullException("member");

                }

     

                PropertyInfo prop = typeof(TSource).GetProperty(member);

                ParameterExpression param = Expression.Parameter(typeof(TSource), "s");

                Expression selector = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);

                MethodInfo sumMethod = typeof(Queryable).GetMethods().First(m => m.Name == "Sum" && m.ReturnType == prop.PropertyType && m.IsGenericMethod);

                return source.Provider.Execute(Expression.Call(null, sumMethod.MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression, Expression.Quote(selector) }));

            }

        }

    ======================================================================================================

     

    Here we have one OfType() method for IQueryable collection and two Sum() methods for both IQueryable and IQueryable<TSource> collections.  For the OfType() method, I think it can only for IQueryable instead of IQueryable<TSource>, because if we can specify the type name here for the compiler, we don’t need the dynamic version, right?  J  As many extension methods in the Dynamic LINQ Library, many methods return IQueryable since all the type information are created during runtime.  Besides, the typeStr parameter should be the full name of the certain type in the current executing assembly, like “Namespace.ClassName”.

     

    For the two Sum() methods, the element type can be retrieved by “typeof(TSource)” or “IQueryable.ElementType”.   Also, the two Sum methods return objects instead of the detailed primitive types, like double, decimal or int.   For both OfType() and Sum() methods, I use Reflection to retrieve the corresponding MethodInfos inside the class Queryable.   Then I refer to the implementation of the Queryable.OfType and Queryable.Sum methods via .NET Reflector and use the method IQueryProvider.Execute(). 

     

    The above methods can be used as:

    ======================================================================================================

    var sum = db.Table1.OfType("Namespace.Table1").Sum("CertainProperty");

    ======================================================================================================

     

    If you have any questions, please feel free to let me know.

     

    Have a great day!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by James 2 Thursday, January 21, 2010 5:43 PM
    Thursday, January 21, 2010 9:54 AM
    Moderator

All replies

  • Hello James,

     

    Welcome to LINQ to SQL forum!

     

    Are you using this Dynamic LINQ Library?  If so, you can refer to the following sample codes to make the dynamic version of OfType() and Sum() methods.  I will explain them later. 

    ======================================================================================================

        public static class MyQueryExtensions

        {

            public static IQueryable OfType(this IQueryable source, string typeStr)

            {

                if (source == null)

                {

                    throw new ArgumentNullException("source");

                }

                if (typeStr == null)

                {

                    throw new ArgumentNullException("typeStr");

                }

     

                Type type = Assembly.GetExecutingAssembly().GetType(typeStr);

                MethodInfo methodOfType = typeof(Queryable).GetMethods().First(m => m.Name == "OfType" && m.IsGenericMethod);

     

                return source.Provider.CreateQuery(Expression.Call(null, methodOfType.MakeGenericMethod(new Type[] { type }), new Expression[] { source.Expression }));

            }

     

            public static object Sum(this IQueryable source, string member)

            {

                if (source == null)

                {

                    throw new ArgumentNullException("source");

                }

                if (member == null)

                {

                    throw new ArgumentNullException("member");

                }

     

                PropertyInfo prop = source.ElementType.GetProperty(member);

                ParameterExpression param = Expression.Parameter(source.ElementType, "s");

                Expression selector = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);

                MethodInfo sumMethod = typeof(Queryable).GetMethods().First(m => m.Name == "Sum" && m.ReturnType == prop.PropertyType && m.IsGenericMethod);

                return source.Provider.Execute(Expression.Call(null, sumMethod.MakeGenericMethod(new Type[] { source.ElementType }), new Expression[] { source.Expression, Expression.Quote(selector) }));

            }

     

            public static object Sum<TSource>(this IQueryable<TSource> source, string member)

            {

                if (source == null)

                {

                    throw new ArgumentNullException("source");

                }

                if (member == null)

                {

                    throw new ArgumentNullException("member");

                }

     

                PropertyInfo prop = typeof(TSource).GetProperty(member);

                ParameterExpression param = Expression.Parameter(typeof(TSource), "s");

                Expression selector = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);

                MethodInfo sumMethod = typeof(Queryable).GetMethods().First(m => m.Name == "Sum" && m.ReturnType == prop.PropertyType && m.IsGenericMethod);

                return source.Provider.Execute(Expression.Call(null, sumMethod.MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression, Expression.Quote(selector) }));

            }

        }

    ======================================================================================================

     

    Here we have one OfType() method for IQueryable collection and two Sum() methods for both IQueryable and IQueryable<TSource> collections.  For the OfType() method, I think it can only for IQueryable instead of IQueryable<TSource>, because if we can specify the type name here for the compiler, we don’t need the dynamic version, right?  J  As many extension methods in the Dynamic LINQ Library, many methods return IQueryable since all the type information are created during runtime.  Besides, the typeStr parameter should be the full name of the certain type in the current executing assembly, like “Namespace.ClassName”.

     

    For the two Sum() methods, the element type can be retrieved by “typeof(TSource)” or “IQueryable.ElementType”.   Also, the two Sum methods return objects instead of the detailed primitive types, like double, decimal or int.   For both OfType() and Sum() methods, I use Reflection to retrieve the corresponding MethodInfos inside the class Queryable.   Then I refer to the implementation of the Queryable.OfType and Queryable.Sum methods via .NET Reflector and use the method IQueryProvider.Execute(). 

     

    The above methods can be used as:

    ======================================================================================================

    var sum = db.Table1.OfType("Namespace.Table1").Sum("CertainProperty");

    ======================================================================================================

     

    If you have any questions, please feel free to let me know.

     

    Have a great day!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by James 2 Thursday, January 21, 2010 5:43 PM
    Thursday, January 21, 2010 9:54 AM
    Moderator
  • Hi Lingzhi,

    Wow! You really save my days, thank you very much!

    I have tried the codes and they worked like a charm. Your explanation is also very helpful and enables me to create the rest of dynamic aggregate functions.

    Again, thank you!

    Regards,
    James.
    Thursday, January 21, 2010 5:46 PM
  • It's my pleasure!  :) 

     

    Have a nice weekend!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Friday, January 22, 2010 1:29 AM
    Moderator