public static IDbSelect Map(
            IDbSelect dbSelect, Type returnType,
            IModelInfoProvider infoProvider, IDbObjectFactory dbFactory, UniqueNameGenerator nameGenerator)
        {
            // If the select returns specified columns, it means there is a constructor in Select,
            // e.g (.Select(d => new { A = d.ABC }))
            // In this case we do not need to add alias to the end result as where will be one in the select
            if (dbSelect.Selection.Any(s => !(s is IDbRefColumn)))
            {
                return(dbSelect);
            }

            var entityInfo = infoProvider.FindEntityInfo(returnType);

            if (!entityInfo.RequirePropertyNameMapping())
            {
                return(dbSelect);
            }

            var alias        = nameGenerator.GenerateAlias(dbSelect, TranslationConstants.SubSelectPrefix, true);
            var newSelectRef = dbFactory.BuildRef(dbSelect, alias);
            var newSelect    = dbFactory.BuildSelect(newSelectRef);

            foreach (var fieldInfo in entityInfo.Columns)
            {
                var column = dbFactory.BuildColumn(
                    newSelectRef, fieldInfo.DbName, fieldInfo.ValType, fieldInfo.PropertyName);

                newSelect.Selection.Add(column);
            }

            return(newSelect);
        }
Exemple #2
0
        public IDbSelect GetLastSelect()
        {
            IDbSelect dbSelect = null;

            var results = new Stack <IDbObject>();

            while (ResultStack.Count > 0)
            {
                var dbObject = ResultStack.Pop();
                results.Push(dbObject);

                dbSelect = dbObject as IDbSelect;
                if (dbSelect != null)
                {
                    break;
                }
            }

            while (results.Count > 0)
            {
                ResultStack.Push(results.Pop());
            }

            return(dbSelect);
        }
        private static IDbSelectable CreateNewSelectableForWrappingSelect(
            IDbSelect dbSelect, IDbSelectable selectable, DbReference dbRef, Expression m,
            IDbObjectFactory dbFactory, UniqueNameGenerator nameGenerator)
        {
            if (dbRef == null)
            {
                return(selectable);
            }

            var oCol = selectable as IDbColumn;

            if (oCol != null)
            {
                return(dbFactory.BuildColumn(dbRef, oCol.GetAliasOrName(), oCol.ValType));
            }

            var oRefCol = selectable as IDbRefColumn;

            if (oRefCol != null)
            {
                return(dbFactory.BuildRefColumn(dbRef, oRefCol.Alias, oRefCol));
            }

            if (selectable is IDbFunc oDbFunc)
            {
                if (string.IsNullOrEmpty(oDbFunc.Alias))
                {
                    oDbFunc.Alias = nameGenerator.GenerateAlias(dbSelect, oDbFunc.Name, true);
                }

                return(dbFactory.BuildColumn(dbRef, oDbFunc.Alias, oDbFunc.ReturnType));
            }

            return(dbFactory.BuildColumn(dbRef, selectable.Alias, typeof(string)));
        }
Exemple #4
0
        private void UpdateSelection(IDbSelect fromSelect, IDbObject selection, DbReference toSelectRef)
        {
            var dbList = selection as IEnumerable <DbKeyValue>;

            if (dbList != null)
            {
                foreach (var dbObj in dbList)
                {
                    UpdateSelection(fromSelect, dbObj, toSelectRef);
                }
                return;
            }

            var keyValue = selection as DbKeyValue;

            selection = keyValue != null ? keyValue.Value : selection;

            var selectable = GetSelectable(fromSelect, selection, toSelectRef);

            if (keyValue != null)
            {
                selectable.Alias = keyValue.Key;
            }

            fromSelect.Selection.Add(selectable);
        }
        protected void CreateAggregation(
            MethodCallExpression m, TranslationState state, UniqueNameGenerator nameGenerator,
            IDbSelect childSelect, IDbFunc dbFunc)
        {
            var dbSelect = (IDbSelect)state.ResultStack.Peek();

            if (childSelect == null)
            {
                state.ResultStack.Push(dbFunc);
                return;
            }

            var alias = nameGenerator.GenerateAlias(dbSelect, dbFunc.Name, true);

            dbFunc.Alias = alias;
            childSelect.Selection.Add(dbFunc);

            var cRef   = dbSelect.Joins.Single(j => ReferenceEquals(j.To.Referee, childSelect)).To;
            var column = _dbFactory.BuildColumn(cRef, alias, m.Method.ReturnType);

            var dbDefaultVal = _dbFactory.BuildConstant(Activator.CreateInstance(m.Method.ReturnType));
            var dbIsNullFunc = _dbFactory.BuildNullCheckFunc(column, dbDefaultVal);

            state.ResultStack.Push(dbIsNullFunc);
        }
 public static IDbSelect Optimize(IDbSelect dbSelect)
 {
     dbSelect = UnwrapUnneededSelect(dbSelect);
     RemoveUnneededSelectAllColumn(dbSelect);
     MergeChildJoins(dbSelect);
     return(dbSelect);
 }
        public static void RemoveUnneededSelectAllColumn(IDbSelect dbSelect, bool subSelectOnly = true)
        {
            if (!subSelectOnly)
            {
                var selectAllColumns = dbSelect.Selection.OfType <IDbRefColumn>().ToArray();
                foreach (var refColumn in selectAllColumns)
                {
                    dbSelect.Selection.Remove(refColumn);
                }
            }

            var subSelect = dbSelect.From?.Referee as IDbSelect;

            if (subSelect != null)
            {
                RemoveUnneededSelectAllColumn(subSelect, false);
            }

            foreach (var dbJoin in dbSelect.Joins)
            {
                subSelect = dbJoin.To.Referee as IDbSelect;
                if (subSelect != null)
                {
                    RemoveUnneededSelectAllColumn(subSelect, false);
                }
            }
        }
Exemple #8
0
        private static IDbJoin MakeJoin(IDbSelect ownerSelect, IDbObject tempSelect, IDbObjectFactory dbFactory, UniqueNameGenerator nameGenerator)
        {
            var joinAlias = nameGenerator.GenerateAlias(ownerSelect, TranslationConstants.SubSelectPrefix);
            var joinTo    = dbFactory.BuildRef(tempSelect, joinAlias);

            return(dbFactory.BuildJoin(joinTo, ownerSelect));
        }
Exemple #9
0
        public string GenerateAlias(IDbSelect dbSelect, string name, bool fullName = false)
        {
            name = name.StartsWith("#") ? name.Remove(0, 1) : name;

            var alias = fullName ? name : name.Substring(0, 1).ToLower();

            int count;

            if (dbSelect == null)
            {
                count = _globalUniqueAliasNames.ContainsKey(alias)
                    ? ++_globalUniqueAliasNames[alias]
                    : _globalUniqueAliasNames[alias] = 0;
            }
            else
            {
                var uniqueNames = _uniqueAliasNames.ContainsKey(dbSelect)
                    ? _uniqueAliasNames[dbSelect]
                    : _uniqueAliasNames[dbSelect] = new Dictionary <string, int>();


                count = uniqueNames.ContainsKey(alias)
                    ? ++uniqueNames[alias]
                    : uniqueNames[alias] = 0;
            }

            return($"{alias}{count}");
        }
Exemple #10
0
        public static void UpdateWhereClause(this IDbSelect dbSelect, IDbBinary whereClause, IDbObjectFactory dbFactory)
        {
            if (whereClause == null)
            {
                return;
            }

            dbSelect.Where = dbSelect.Where.UpdateBinary(whereClause, dbFactory);
        }
Exemple #11
0
 public override IDbTempTable BuildTempTable(string tableName, IDbSelect sourceSelect = null)
 {
     return(new SqliteTempTable
     {
         TableName = tableName,
         SourceSelect = sourceSelect,
         OutputOption = OutputOption
     });
 }
 public virtual IDbTempTable BuildTempTable(string tableName, IDbSelect sourceSelect = null)
 {
     return(new SqlTempTable
     {
         TableName = tableName,
         SourceSelect = sourceSelect,
         OutputOption = OutputOption
     });
 }
        public static void MergeChildJoins(IDbSelect dbSelect)
        {
            var joins = dbSelect.Joins.Where(j => j.To.Referee is IDbSelect).ToArray();

            if (joins.Length == 0)
            {
                return;
            }

            foreach (var dbJoin in joins)
            {
                MergeChildJoins((IDbSelect)dbJoin.To.Referee);
            }

            var colDict = dbSelect.Selection.
                          SelectMany(s => s.GetDbObjects <IDbColumn>()).
                          Distinct().
                          ToDictionary(s => s.GetAliasOrName(), s => s);

            var selectDict = new Dictionary <string, IDbJoin>();

            foreach (var dbJoin in joins)
            {
                var childSelect = (IDbSelect)dbJoin.To.Referee;

                var hashKey = childSelect.ToMergeKey();
                if (selectDict.ContainsKey(hashKey))
                {
                    var mergedJoin   = selectDict[hashKey];
                    var mergedSelect = (IDbSelect)mergedJoin.To.Referee;

                    var colLookUp = mergedSelect.Selection.ToLookup(s => s.GetAliasOrName());
                    var columns   = childSelect.Selection.Where(s => !colLookUp.Contains(s.GetAliasOrName()));
                    foreach (var selectable in columns)
                    {
                        var column = colDict[selectable.GetAliasOrName()];
                        column.Ref = mergedJoin.To;
                        mergedSelect.Selection.Add(selectable);
                    }
                }
                else
                {
                    selectDict[hashKey] = dbJoin;
                }
            }

            var lookUp = selectDict.Values.ToLookup(v => v);

            foreach (var dbJoin in joins)
            {
                if (!lookUp.Contains(dbJoin))
                {
                    dbSelect.Joins.Remove(dbJoin);
                }
            }
        }
Exemple #14
0
        private void ReLinkToChildSelect(IDbSelect dbSelect, IDbSelect childSelect)
        {
            var joinToRelink = dbSelect.Joins.SingleOrDefault(j => ReferenceEquals(j.To.Referee, childSelect.From.Referee));

            if (joinToRelink == null)
            {
                return;
            }
            joinToRelink.To = _dbFactory.BuildRef(childSelect, joinToRelink.To.Alias);
        }
        public override IDbTempTable BuildTempTable(string tableName, IDbSelect sourceSelect = null)
        {
            var sqlTable = new MySqlTempTable
            {
                TableName    = tableName,
                SourceSelect = sourceSelect,
                OutputOption = OutputOption
            };

            return(sqlTable);
        }
Exemple #16
0
        private static void UpdateIncludeSelectAndProcessToNodes(
            IncludeNode graphNode, IDbSelect includedSelect, IModelInfoProvider infoProvider,
            IDbObjectFactory dbFactory, UniqueNameGenerator nameGenerator, AbstractMethodTranslator[] addons)
        {
            // create temp table
            var entityRef   = includedSelect.GetReturnEntityRef();
            var returnTable = (IDbTable)entityRef.Referee;

            var newIncludedSelect = dbFactory.BuildSelect(returnTable);

            newIncludedSelect.From.Alias = nameGenerator.GenerateAlias(newIncludedSelect, returnTable.TableName);

            var tempTableName = TranslationConstants.TempTablePreix + nameGenerator.GenerateAlias(null, returnTable.TableName, true);
            var tempTable     = dbFactory.BuildTempTable(tempTableName, includedSelect);

            var tempSelect = dbFactory.BuildSelect(tempTable);

            tempSelect.From.Alias = nameGenerator.GenerateAlias(tempSelect, tempTable.TableName);

            var joinToTemp = MakeJoin(newIncludedSelect, tempSelect, dbFactory, nameGenerator);
            var joinTo     = joinToTemp.To;

            newIncludedSelect.Joins.Add(joinToTemp);

            foreach (var pk in returnTable.PrimaryKeys)
            {
                var fromPkCol = dbFactory.BuildColumn(entityRef, pk.Name, pk.ValType);
                includedSelect.Selection.Add(fromPkCol);

                var toPkCol = dbFactory.BuildColumn(tempSelect.From, pk.Name, pk.ValType);
                tempSelect.Selection.Add(toPkCol);
                tempSelect.GroupBys.Add(toPkCol);

                toPkCol = dbFactory.BuildColumn(joinTo, pk.Name, pk.ValType);
                var binary = dbFactory.BuildBinary(fromPkCol, DbOperator.Equal, toPkCol);
                joinToTemp.Condition = joinToTemp.Condition.UpdateBinary(binary, dbFactory);
            }

            var orderCol = dbFactory.BuildColumn(tempSelect.From, tempTable.RowNumberColumnName, typeof(int));

            tempSelect.Selection.Add(orderCol);

            orderCol = dbFactory.BuildColumn(joinTo, tempTable.RowNumberColumnName, typeof(int));
            newIncludedSelect.OrderBys.Add(orderCol);

            graphNode.Select    = newIncludedSelect;
            graphNode.TempTable = tempTable;

            foreach (var toNode in graphNode.ToNodes)
            {
                TranslateGraphNode(toNode, infoProvider, dbFactory, nameGenerator, addons);
            }
        }
Exemple #17
0
        /// <summary> Translate to SQL </summary>
        public override void Translate(
            MethodCallExpression m, TranslationState state, UniqueNameGenerator nameGenerator)
        {
            var dbExpression = GetAggregationTarget(m, state);

            IDbSelect childSelect = null;

            if (!m.GetCaller().Type.IsGrouping())
            {
                childSelect = state.ResultStack.Pop() as IDbSelect;
            }

            // if the aggregation does not have expression, it means
            // the caller of the aggregation method must be a Select method call
            // In this case, the actual expression that we need to aggregate on,
            // will be inside the child select statement
            if (dbExpression == null && childSelect != null)
            {
                // to get the actual expression, we need to first unwrap the child select
                // because the translation of Select call always wrap the actual select
                childSelect = (IDbSelect)childSelect.From.Referee;

                dbExpression = childSelect.Selection.Last(
                    s => string.IsNullOrEmpty(s.Alias) ||
                    !s.Alias.EndsWith(TranslationConstants.JoinKeySuffix));

                childSelect.Selection.Remove(dbExpression);
                childSelect.GroupBys.Remove(dbExpression);
            }

            if (dbExpression == null)
            {
                throw new NotSupportedException("Can not aggregate.");
            }

            if (!(dbExpression is IDistinctable))
            {
                throw new NotSupportedException("Expression must be Distinctable");
            }

            var distinctable = (IDistinctable)dbExpression;

            distinctable.IsDistinct = true;

            var dbFunc = _dbFactory.BuildFunc("count", true, m.Method.ReturnType, dbExpression);

            CreateAggregation(m, state, nameGenerator, childSelect, dbFunc);
        }
        public IDbJoin BuildJoin(
            DbReference joinTo, IDbSelect dbSelect, IDbBinary condition = null,
            DbJoinType dbJoinType = DbJoinType.Inner)
        {
            var dbJoin = new SqlJoin
            {
                To        = joinTo,
                Condition = condition,
                Type      = dbJoinType
            };

            joinTo.OwnerSelect = dbSelect;
            joinTo.OwnerJoin   = dbJoin;

            return(dbJoin);
        }
Exemple #19
0
        public override void Translate(
            MethodCallExpression m, TranslationState state, UniqueNameGenerator nameGenerator)
        {
            var predicate = BuildCondition(m, state);

            IDbSelect childSelect = null;

            if (!m.GetCaller().Type.IsGrouping())
            {
                childSelect = state.ResultStack.Pop() as IDbSelect;
            }

            var dbCountFunc = _dbFactory.BuildFunc(m.Method.Name.ToLower(), true, m.Method.ReturnType, predicate);

            CreateAggregation(m, state, nameGenerator, childSelect, dbCountFunc);
        }
Exemple #20
0
        protected void CreateAggregation(
            MethodCallExpression m, TranslationState state, UniqueNameGenerator nameGenerator,
            IDbSelect childSelect, IDbFunc dbFunc)
        {
            var dbSelect = (IDbSelect)state.ResultStack.Peek();

            if (childSelect == null)
            {
                state.ResultStack.Push(dbFunc);
                return;
            }

            var alias = nameGenerator.GenerateAlias(dbSelect, dbFunc.Name, true);

            dbFunc.Alias = alias;
            childSelect.Selection.Add(dbFunc);

            /**
             * Aggregation can happen after a method that generate new select.
             * In this case, join from the main select to the child select will not be
             * updated yet at this stage, so we need to correct the join to on the
             * correct child select statment.
             * For example:
             * var query = db.Blogs
             *     .Where(b => b.BlogId > 0)
             *     .Select(b => new
             *      {
             *          b.BlogId,
             *          Cnt = b.Posts.Select(p => p.Title).Distinct().Count()
             *      });
             * `b.Posts.Select(p => p.Title).Distinct()` will create a new child select and
             * it will not be the one that the main select is currently targeting, so we
             * need to correct the join target.
             */
            ReLinkToChildSelect(dbSelect, childSelect);

            var cRef   = dbSelect.Joins.Single(j => ReferenceEquals(j.To.Referee, childSelect)).To;
            var column = _dbFactory.BuildColumn(cRef, alias, m.Method.ReturnType);

            var dbDefaultVal = _dbFactory.BuildConstant(Activator.CreateInstance(m.Method.ReturnType));
            var dbIsNullFunc = _dbFactory.BuildNullCheckFunc(m.Method.ReturnType, column, dbDefaultVal);

            state.ResultStack.Push(dbIsNullFunc);
        }
Exemple #21
0
        private IDbSelectable GetSelectable(IDbSelect fromSelect, IDbObject selection, DbReference toSelectRef)
        {
            var dbRef = selection as DbReference;

            if (dbRef != null)
            {
                IDbRefColumn toRefCol = null;
                if (dbRef.OwnerSelect != fromSelect)
                {
                    var toSelect = (IDbSelect)toSelectRef.Referee;
                    toRefCol = _dbFactory.BuildRefColumn(dbRef);

                    toSelect.Selection.Add(toRefCol);
                    dbRef = toSelectRef;
                }

                var refColumn = _dbFactory.BuildRefColumn(dbRef);
                refColumn.RefTo = toRefCol;
                return(refColumn);
            }

            var column = selection as IDbColumn;

            if (column != null)
            {
                if (column.Ref.OwnerSelect != fromSelect)
                {
                    var toSelect = (IDbSelect)toSelectRef.Referee;
                    toSelect.Selection.Add(column);

                    column     = _dbFactory.BuildColumn(column);
                    column.Ref = toSelectRef;
                }

                return(column);
            }

            throw new NotSupportedException();
        }
        public static IDbSelect UnwrapUnneededSelect(IDbSelect dbSelect)
        {
            while (true)
            {
                if (!CanUnwrapSelect(dbSelect))
                {
                    return(dbSelect);
                }

                var unwrapedSelect = (IDbSelect)dbSelect.From.Referee;
                if (!dbSelect.Selection.Any())
                {
                    dbSelect = unwrapedSelect;
                    continue;
                }

                // re add columns with outer select's order
                // there are two ways to lookup the selectable in the unwraped select
                // for normally column, we can use the name the column to search aginst the
                // alais name in the unwrapped select
                // for RefColumn, we can use the RefTo property to look for the column it refers to
                var colDict = unwrapedSelect.Selection.
                              Where(s => s.GetAliasOrName() != null).
                              ToDictionary(s => s.GetAliasOrName(), s => s);

                unwrapedSelect.Selection.Clear();
                foreach (var selectable in dbSelect.Selection)
                {
                    var innnerCol = (selectable as IDbRefColumn)?.RefTo ?? colDict[selectable.GetNameOrAlias()];
                    innnerCol.Alias = selectable.GetAliasOrName();
                    unwrapedSelect.Selection.Add(innnerCol);
                }

                unwrapedSelect.Selection.IsDistinct = dbSelect.Selection.IsDistinct;

                dbSelect = unwrapedSelect;
            }
        }
Exemple #23
0
        private static void UpdateFromNodeTempTable(
            IncludeNode fromNode, IDbObject dbObject, IDbSelect includedSelect,
            IDbObjectFactory dbFactory, UniqueNameGenerator nameGenerator)
        {
            var fromSelect = fromNode.Select;

            var dbJoin = fromSelect.Joins.Single(
                j => dbObject is DbReference ? ReferenceEquals(j.To, dbObject) : ReferenceEquals(j.To.Referee, dbObject));

            // remove the join to included relation from fromSelect
            fromSelect.Joins.Remove(dbJoin);

            if (dbObject is IDbSelect)
            {
                var refCol = includedSelect.Selection.Single(c => c is IDbRefColumn);
                includedSelect.Selection.Remove(refCol);
            }

            var keys     = dbJoin.Condition.GetDbObjects <IDbColumn>().ToArray();
            var fromKeys = keys.Where(c => !ReferenceEquals(c.Ref, dbJoin.To)).ToArray();
            var toKeys   = keys.Where(c => ReferenceEquals(c.Ref, dbJoin.To)).ToArray();

            var tempTable    = fromNode.TempTable;
            var sourceSelect = tempTable.SourceSelect;

            var fromRef   = sourceSelect.GetReturnEntityRef();
            var returnRef = includedSelect.GetReturnEntityRef();

            var tempSelect = dbFactory.BuildSelect(tempTable);

            tempSelect.From.Alias = nameGenerator.GenerateAlias(tempSelect, tempTable.TableName);

            var joinToTemp = MakeJoin(includedSelect, tempSelect, dbFactory, nameGenerator);

            includedSelect.Joins.Add(joinToTemp);

            for (var i = 0; i < fromKeys.Length; i++)
            {
                var fromKey = fromKeys[i];
                var toKey   = toKeys[i];

                var fromPkCol = dbFactory.BuildColumn(fromRef, fromKey.Name, fromKey.ValType);
                sourceSelect.Selection.Add(fromPkCol);

                var tempPkCol = dbFactory.BuildColumn(tempSelect.From, fromKey.Name, fromKey.ValType);
                tempSelect.Selection.Add(tempPkCol);
                tempSelect.GroupBys.Add(tempPkCol);

                if (dbObject is IDbSelect)
                {
                    var key = toKey;
                    toKey = (IDbColumn)includedSelect.Selection.Single(c => c.GetAliasOrName() == key.GetNameOrAlias());
                    includedSelect.Selection.Remove(toKey);
                    includedSelect.GroupBys.Remove(toKey);
                }

                fromPkCol = dbFactory.BuildColumn(joinToTemp.To, fromKey.Name, fromKey.ValType);
                var toPkCol = dbFactory.BuildColumn(returnRef, toKey.Name, toKey.ValType);
                var binary  = dbFactory.BuildBinary(toPkCol, DbOperator.Equal, fromPkCol);
                joinToTemp.Condition = joinToTemp.Condition.UpdateBinary(binary, dbFactory);
            }
        }
        public static DbReference GetReturnEntityRef(this IDbSelect dbSelect)
        {
            var entityRefCol = dbSelect.Selection.SingleOrDefault(c => c is IDbRefColumn);

            return(entityRefCol != null ? entityRefCol.Ref : dbSelect.From);
        }
 private static bool CanUnwrapSelect(IDbSelect dbSelect)
 {
     return(dbSelect.From.Referee is IDbSelect && dbSelect.Where == null &&
            !dbSelect.Joins.Any() && !dbSelect.OrderBys.Any() && !dbSelect.GroupBys.Any() &&
            dbSelect.Selection.All(s => s is IDbColumn || s is IDbRefColumn));
 }
Exemple #26
0
 public DbSelectableCollection(IDbSelect owner)
 {
     _owner = owner;
 }
Exemple #27
0
        /// Create a join for the relation
        /// For parent relation, we create a join that joins to the parent table
        /// For child relation, we will create a sub select that returns the child table,
        /// and then joins to the sub select.
        /// The reason for joining to sub select for child relation, is that we want to be
        /// able to group on the join key, so that we will not repeat the parent row.
        private IDbJoin GetOrCreateJoin(EntityRelation relation, DbReference fromRef, IDbRefColumn refCol)
        {
            var dbSelect = fromRef.OwnerSelect;
            var tupleKey = Tuple.Create(dbSelect, relation);

            if (!relation.IsChildRelation && _state.CreatedJoins.ContainsKey(tupleKey))
            {
                return(_state.CreatedJoins[tupleKey]);
            }

            var toEntity = relation.ToEntity;
            var dbTable  = _dbFactory.BuildTable(toEntity);

            DbReference joinTo;
            DbReference childRef    = null;
            IDbSelect   childSelect = null;

            // Create the join. For parent join, we just need to join to a Ref to the table
            // For child relation, we will firstly create a sub select that return the child table
            // and then join to then sub select
            if (!relation.IsChildRelation)
            {
                var tableAlias = _nameGenerator.GenerateAlias(dbSelect, dbTable.TableName);
                joinTo = _dbFactory.BuildRef(dbTable, tableAlias);
            }
            else
            {
                childRef       = _dbFactory.BuildRef(dbTable);
                childSelect    = _dbFactory.BuildSelect(childRef);
                childRef.Alias = _nameGenerator.GenerateAlias(childSelect, dbTable.TableName);

                var tableAlias = _nameGenerator.GenerateAlias(dbSelect, TranslationConstants.SubSelectPrefix, true);
                joinTo = _dbFactory.BuildRef(childSelect, tableAlias);
            }

            var dbJoin = _dbFactory.BuildJoin(joinTo, dbSelect);

            dbSelect.Joins.Add(dbJoin);

            // build join condition
            IDbBinary condition = null;

            for (var i = 0; i < relation.FromKeys.Count; i++)
            {
                var fromKey = relation.FromKeys[i];
                var toKey   = relation.ToKeys[i];

                var fromColumn = _dbFactory.BuildColumn(fromRef, fromKey.DbName, fromKey.ValType);
                var toColumn   = _dbFactory.BuildColumn(joinTo, toKey.DbName, toKey.ValType);

                // If we have created a sub for child relation, we need to the columns
                // that are used in join condition selected from the sub select.
                if (childRef != null && childSelect != null)
                {
                    var alias       = _nameGenerator.GenerateAlias(childSelect, toKey.DbName + TranslationConstants.JoinKeySuffix, true);
                    var childColumn = _dbFactory.BuildColumn(childRef, toKey.DbName, toKey.ValType, alias, true);

                    /**
                     * We need to also put the join key in the group of the sub select.
                     * This is to make sure the sub select is grouped by the key so that
                     * the parent (outer select) will not be repeated
                     * This operation needs to happen here not in the aggregation method call.
                     * The reason is that in aggregtion method calls we do not know which column
                     * from the entity is used in relation, so they will not be able to create
                     * the correct column
                     */
                    childSelect.Selection.Add(_dbFactory.BuildRefColumn(childRef));
                    childSelect.Selection.Add(childColumn);
                    childSelect.GroupBys.Add(childColumn);

                    toColumn.Name  = alias;
                    toColumn.Alias = string.Empty;
                }

                // if the relation is found on a fromRef which is referring a sub-select,
                // it means the from key of the join is not on a table but a derived select.
                // In this case, we need to add the from key into the derived select, as we will
                // be using it in the join
                if (fromRef.Referee is IDbSelect)
                {
                    var alias = _nameGenerator.GenerateAlias(dbSelect, toKey.DbName + TranslationConstants.JoinKeySuffix, true);
                    fromColumn.Name  = alias;
                    fromColumn.Alias = string.Empty;

                    // try to recursively add the join key to all connected sub select.
                    refCol.RefTo?.AddToReferedSelect(_dbFactory, fromKey.DbName, fromKey.ValType, alias);
                }

                var binary = _dbFactory.BuildBinary(fromColumn, DbOperator.Equal, toColumn);
                condition = condition.UpdateBinary(binary, _dbFactory);
            }

            dbJoin.Condition = condition;

            // all relations need to follow the join type
            if (fromRef.OwnerJoin != null)
            {
                dbJoin.Type = fromRef.OwnerJoin.Type;
            }

            if (relation.IsChildRelation)
            {
                dbJoin.Type = DbJoinType.LeftOuter;
            }

            return(_state.CreatedJoins[tupleKey] = dbJoin);
        }