public static IQueryable <QEntity> LeftJoin <QEntity, QKey, JEntity, JKey>( //LeftJoin == + .DefaultIfEmpty()
            this IQueryable <QEntity> query,
            LinqToDB.ITable <JEntity> table,
            Expression <Func <QEntity, QKey> > queryKey,
            Expression <Func <JEntity, JKey> > joinKey,
            Expression <Func <QEntity, JEntity> > resultSelectorExpression
            )
        {
            var joinPropertyInfo = ((PropertyInfo)((MemberExpression)joinKey.Body).Member);

            var queryParameter          = Expression.Parameter(typeof(QEntity), "query");
            var joinCollectionParameter = Expression.Parameter(typeof(IQueryable <JEntity>), "joinCollection"); //ex. (l, r) => ...

            //join => query.ForeignKeyId == (queryType)join.Id
            var wherePredicate = CreateWherePredicate <QEntity, QKey, JEntity>(queryParameter, queryKey, joinPropertyInfo.Name);

            var whereCall = CreateWhereCall <JEntity>(joinCollectionParameter, wherePredicate);

            var defaultIfEmptyMethodInfo        = GetDefaultIfEmpty();
            var genericDefaultIfEmptyMethodInfo = defaultIfEmptyMethodInfo.MakeGenericMethod(typeof(JEntity));

            var defaultIfEmptyCall = Expression.Call(genericDefaultIfEmptyMethodInfo, whereCall);

            //query => Queryable.Where(joinCollection, join => query.ForeignKeyId == (queryType)join.Id)
            var collectionSelectorExpression = CreateCollectionSelectorExpression <QEntity, JEntity>(queryParameter, defaultIfEmptyCall);

            //(queryCollection, joinCollection) =>
            //	Queryable.SelectMany(queryCollection, query =>
            //		Queryable.Where(joinCollection, join => query.ForeignKeyId == (queryType)join.Id),
            //	(i, j) => i);
            var expression = CreateExpression(joinCollectionParameter, collectionSelectorExpression, Bind(resultSelectorExpression));

            return(expression.Compile()(query, table));
        }
        public static IQueryable <QEntity> Join <QEntity, QKey, JEntity, JKey>( //LeftJoin == + .DefaultIfEmpty()
            this IQueryable <QEntity> query,
            LinqToDB.ITable <JEntity> table,
            Expression <Func <QEntity, QKey> > queryKey,
            Expression <Func <JEntity, JKey> > joinKey,
            Expression <Func <QEntity, JEntity> > resultSelectorExpression
            )
        {
            var joinPropertyInfo = ((PropertyInfo)((MemberExpression)joinKey.Body).Member);

            var queryParameter          = Expression.Parameter(typeof(QEntity), "query");
            var joinCollectionParameter = Expression.Parameter(typeof(IQueryable <JEntity>), "joinCollection"); //ex. (l, r) => ...

            //join => query.ForeignKeyId == (queryType)join.Id
            var wherePredicate = CreateWherePredicate <QEntity, QKey, JEntity>(queryParameter, queryKey, joinPropertyInfo.Name);

            var whereCall = CreateWhereCall <JEntity>(joinCollectionParameter, wherePredicate);

            //query => Queryable.Where(joinCollection, join => query.ForeignKeyId == (queryType)join.Id)
            var collectionSelectorExpression = CreateCollectionSelectorExpression <QEntity, JEntity>(queryParameter, whereCall);

            //var resultBinding = Bind(resultSelectorExpression);
            //Bind<User, Street>((u, s) => new User { Address = new Address { Street = s }});

            //resultSelectorExpression.ToString().Dump();
            //resultBinding.ToString().Dump();

            //(queryCollection, joinCollection) =>
            //	Queryable.SelectMany(queryCollection, query =>
            //		Queryable.Where(joinCollection, join => query.ForeignKeyId == (queryType)join.Id),
            //	(i, j) => i);
            var expression = CreateExpression(joinCollectionParameter, collectionSelectorExpression, Bind(resultSelectorExpression));

            //expression.Dump(1);
            return(expression.Compile()(query, table));
        }