private static IQueryable <TSource> CallGenericSelectMethod <TSource>(IQueryable <TSource> source, IEnumerable <string> columns, IResourceFactory resourceFactory)
        {
            var sourceType       = typeof(TSource);
            var parameter        = Expression.Parameter(source.ElementType, "x");
            var sourceProperties = new HashSet <string>();

            // Store all property names to it's own related property (name as key)
            var nestedTypesAndProperties = new Dictionary <string, HashSet <string> >();

            foreach (var column in columns)
            {
                var props = column.Split('.');
                if (props.Length > 1) // Nested property
                {
                    if (nestedTypesAndProperties.TryGetValue(props[0], out var properties) == false)
                    {
                        nestedTypesAndProperties.Add(props[0], new HashSet <string> {
                            nameof(Identifiable.Id), props[1]
                        });
                    }
                    else
                    {
                        properties.Add(props[1]);
                    }
                }
                else
                {
                    sourceProperties.Add(props[0]);
                }
            }

            // Bind attributes on TSource
            var sourceBindings = sourceProperties.Select(prop => Expression.Bind(sourceType.GetProperty(prop), Expression.PropertyOrField(parameter, prop))).ToList();

            // Bind attributes on nested types
            var nestedBindings = new List <MemberAssignment>();

            foreach (var item in nestedTypesAndProperties)
            {
                var nestedProperty     = sourceType.GetProperty(item.Key);
                var nestedPropertyType = nestedProperty.PropertyType;
                // [HasMany] attribute
                Expression bindExpression;
                if (nestedPropertyType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(nestedPropertyType))
                {
                    var collectionElementType = nestedPropertyType.GetGenericArguments().Single();
                    // {y}
                    var nestedParameter = Expression.Parameter(collectionElementType, "y");
                    nestedBindings = item.Value.Select(prop => Expression.Bind(
                                                           collectionElementType.GetProperty(prop), Expression.PropertyOrField(nestedParameter, prop))).ToList();

                    // { new Item() }
                    var newNestedExp  = resourceFactory.CreateNewExpression(collectionElementType);
                    var initNestedExp = Expression.MemberInit(newNestedExp, nestedBindings);
                    // { y => new Item() {Id = y.Id, Name = y.Name}}
                    var body = Expression.Lambda(initNestedExp, nestedParameter);
                    // { x.Items }
                    Expression propertyExpression = Expression.Property(parameter, nestedProperty.Name);
                    // { x.Items.Select(y => new Item() {Id = y.Id, Name = y.Name}) }
                    Expression selectMethod = Expression.Call(
                        typeof(Enumerable),
                        "Select",
                        new[] { collectionElementType, collectionElementType },
                        propertyExpression, body);

                    var enumerableOfElementType    = typeof(IEnumerable <>).MakeGenericType(collectionElementType);
                    var typedCollection            = nestedPropertyType.ToConcreteCollectionType();
                    var typedCollectionConstructor = typedCollection.GetConstructor(new[] { enumerableOfElementType });

                    // { new HashSet<Item>(x.Items.Select(y => new Item() {Id = y.Id, Name = y.Name})) }
                    bindExpression = Expression.New(typedCollectionConstructor, selectMethod);
                }
                // [HasOne] attribute
                else
                {
                    // {x.Owner}
                    var srcBody = Expression.PropertyOrField(parameter, item.Key);
                    foreach (var nested in item.Value)
                    {
                        // {x.Owner.Name}
                        var nestedBody = Expression.PropertyOrField(srcBody, nested);
                        var propInfo   = nestedPropertyType.GetProperty(nested);
                        nestedBindings.Add(Expression.Bind(propInfo, nestedBody));
                    }
                    // { new Owner() }
                    var newExp = resourceFactory.CreateNewExpression(nestedPropertyType);
                    // { new Owner() { Id = x.Owner.Id, Name = x.Owner.Name }}
                    var newInit = Expression.MemberInit(newExp, nestedBindings);

                    // Handle nullable relationships
                    // { Owner = x.Owner == null ? null : new Owner() {...} }
                    bindExpression = Expression.Condition(
                        Expression.Equal(srcBody, Expression.Constant(null)),
                        Expression.Convert(Expression.Constant(null), nestedPropertyType),
                        newInit
                        );
                }

                sourceBindings.Add(Expression.Bind(nestedProperty, bindExpression));
                nestedBindings.Clear();
            }

            var newExpression = resourceFactory.CreateNewExpression(sourceType);
            var sourceInit    = Expression.MemberInit(newExpression, sourceBindings);
            var finalBody     = Expression.Lambda(sourceInit, parameter);

            return(source.Provider.CreateQuery <TSource>(Expression.Call(
                                                             typeof(Queryable),
                                                             "Select",
                                                             new[] { source.ElementType, typeof(TSource) },
                                                             source.Expression,
                                                             Expression.Quote(finalBody))));
        }