public SqlExpression <T> LeftJoin <Source, Target>(Expression <Func <Source, Target, bool> > joinExpr, TableOptions options) =>
 InternalJoin("LEFT JOIN", joinExpr, options);
 public SqlExpression <T> LeftJoin <Target>(Expression <Func <T, Target, bool> > joinExpr, TableOptions options) =>
 InternalJoin("LEFT JOIN", joinExpr, options ?? throw new ArgumentNullException(nameof(options)));
        protected virtual SqlExpression <T> InternalJoin(string joinType, Expression joinExpr, ModelDefinition sourceDef, ModelDefinition targetDef, TableOptions options = null)
        {
            PrefixFieldWithTableName = true;

            //Changes how Sql Expressions are generated.
            useFieldName = true;
            sep          = " ";

            var joinFormat = options?.JoinFormat;

            if (options?.Alias != null) //Set joinAlias
            {
                options.ParamName = joinExpr is LambdaExpression l && l.Parameters.Count == 2
                    ? l.Parameters[1].Name
                    : null;
                if (options.ParamName != null)
                {
                    joinFormat       = null;
                    options.ModelDef = targetDef;
                    joinAlias        = options;
                }
            }


            if (!tableDefs.Contains(sourceDef))
            {
                tableDefs.Add(sourceDef);
            }
            if (!tableDefs.Contains(targetDef))
            {
                tableDefs.Add(targetDef);
            }

            var isCrossJoin = "CROSS JOIN" == joinType;

            var sqlExpr = joinExpr != null
                ? InternalCreateSqlFromExpression(joinExpr, isCrossJoin)
                : InternalCreateSqlFromDefinitions(sourceDef, targetDef, isCrossJoin);

            var joinDef = tableDefs.Contains(targetDef) && !tableDefs.Contains(sourceDef)
                ? sourceDef
                : targetDef;

            FromExpression += joinFormat != null
                ? $" {joinType} {joinFormat(DialectProvider, joinDef, sqlExpr)}"
                : joinAlias != null
                    ? $" {joinType} {SqlTable(joinDef)} AS {DialectProvider.GetQuotedName(joinAlias.Alias)} {sqlExpr}"
                    : $" {joinType} {SqlTable(joinDef)} {sqlExpr}";


            if (joinAlias != null) //Unset joinAlias
            {
                joinAlias = null;
                if (options != null)
                {
                    options.ParamName = null;
                    options.ModelDef  = null;
                }
            }

            return(this);
        }
        public SqlExpression <T> Join <Target>(Expression <Func <T, Target, bool> > joinExpr, TableOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (options.Expression != null)
            {
                throw new ArgumentException("Can't set both Join Expression and TableOptions Expression");
            }

            return(InternalJoin("INNER JOIN", joinExpr, options));
        }
        protected SqlExpression <T> InternalJoin <Source, Target>(string joinType, Expression <Func <Source, Target, bool> > joinExpr, TableOptions options = null)
        {
            var sourceDef = typeof(Source).GetModelDefinition();
            var targetDef = typeof(Target).GetModelDefinition();

            return(InternalJoin(joinType, joinExpr, sourceDef, targetDef, options));
        }