Example #1
0
        internal static ICollection <FilteredIncludeExpression> MapFilteredIncludes <TModel, TData>(this ICollection <FilteredIncludeExpression> filteredIncludes, IMapper mapper)
        {
            if (filteredIncludes == null)
            {
                return(null);
            }

            LambdaExpression GetFilter(LambdaExpression nextFilter, Type sourceMemberType, Type destMemberType)
            {
                if (nextFilter == null)
                {
                    return(null);
                }

                return((LambdaExpression)mapper.Map
                       (
                           nextFilter,
                           typeof(Expression <>).MakeGenericType
                           (
                               new Type[]
                {
                    sourceMemberType.IsList()
                                ? typeof(Func <,>).MakeGenericType(new Type[] { sourceMemberType.GetUnderlyingElementType(), typeof(bool) })
                                : typeof(Func <,>).MakeGenericType(new Type[] { sourceMemberType, typeof(bool) })
                }
                           ),
                           typeof(Expression <>).MakeGenericType
                           (
                               new Type[]
                {
                    destMemberType.IsList()
                                ? typeof(Func <,>).MakeGenericType(new Type[] { destMemberType.GetUnderlyingElementType(), typeof(bool) })
                                : typeof(Func <,>).MakeGenericType(new Type[] { destMemberType, typeof(bool) })
                }
                           )
                       ));
            }

            return(filteredIncludes.Aggregate(new List <FilteredIncludeExpression>(), (list, next) =>
            {
                if (next.Include == null)
                {
                    throw new ArgumentNullException("FilteredIncludeExpression.Include is required.");
                }

                //Map with member converted to object
                LambdaExpression mappedInclude = mapper.MapExpressionAsInclude <Expression <Func <TData, object> > >(next.Include);

                //Get the member expression as an "uncast" member expression
                MemberExpression mappedIncludeMemberExpression = mappedInclude.Body.GetMemberExpression();

                //Uncast expression's member type for the selected member
                Type destMemberType = mappedIncludeMemberExpression.GetMemberType();

                //Uncast expression's member type for the source's selected member
                Type sourceMemberType = next.Include.Body.GetMemberExpression().GetMemberType();

                //Recreate the lanbda expression so it is strongly typed.  For collections the type must be IEnumerable<TProperty>.
                //EntityEntry<T>.Collection expects an expression selector of type Expression<Func<T, IEnumerable<TProperty>>>
                mappedInclude = Expression.Lambda
                                (
                    typeof(Func <,>).MakeGenericType
                    (
                        new Type[]
                {
                    typeof(TData),
                    destMemberType.IsList()
                                ? typeof(IEnumerable <>).MakeGenericType(new Type[] { destMemberType.GetUnderlyingElementType() })
                                : destMemberType
                }
                    ),
                    mappedIncludeMemberExpression,
                    mappedInclude.Parameters[0]
                                );


                list.Add
                (
                    new FilteredIncludeExpression
                {
                    Include = mappedInclude,
                    Filter = GetFilter(next.Filter, sourceMemberType, destMemberType),
                    FilteredIncludes = next.FilteredIncludes == null ? null : (ICollection <FilteredIncludeExpression>)MAP_FILTERED_INCLUDES_METHOD.GetMethod().MakeGenericMethod
                                       (
                        /*TModel*/ sourceMemberType.IsList() ? sourceMemberType.GetUnderlyingElementType() : sourceMemberType,   //should not be a literal type.  A flattened include should not have child includes
                        /*TData*/ destMemberType.IsList() ? destMemberType.GetUnderlyingElementType() : destMemberType
                                       ).Invoke(null, new object[] { next.FilteredIncludes, mapper })
                }
                );
                return list;
            }));
        }