/// <summary>
        /// Registers an association
        /// </summary>
        /// <param name="tableExpression">The table holding the member, to become the joinedTable</param>
        /// <param name="tableMemberInfo"></param>
        /// <param name="otherType"></param>
        /// <param name="builderContext"></param>
        /// <returns></returns>
        public virtual TableExpression RegisterAssociation(TableExpression tableExpression, MemberInfo tableMemberInfo,
                                                           Type otherType, BuilderContext builderContext)
        {
            IList <MemberInfo> otherKeys;
            TableJoinType      joinType;
            string             joinID;
            var theseKeys = DataMapper.GetAssociation(tableExpression, tableMemberInfo, otherType, out otherKeys,
                                                      out joinType, out joinID, builderContext.QueryContext.DataContext);

            // if the memberInfo has no corresponding association, we get a null, that we propagate
            if (theseKeys == null)
            {
                return(null);
            }

            // the current table has the foreign key, the other table the referenced (usually primary) key
            if (theseKeys.Count != otherKeys.Count)
            {
                throw Error.BadArgument("S0128: Association arguments (FK and ref'd PK) don't match");
            }

            // we first create the table, with the JoinID, and we MUST complete the table later, with the Join() method
            var otherTableExpression = new TableExpression(otherType, DataMapper.GetTableName(otherType, builderContext.QueryContext.DataContext), joinID);

            Expression joinExpression = null;

            var createdColumns = new List <ColumnExpression>();

            for (int keyIndex = 0; keyIndex < theseKeys.Count; keyIndex++)
            {
                // joinedKey is registered, even if unused by final select (required columns will be filtered anyway)
                Expression otherKey = RegisterColumn(otherTableExpression, otherKeys[keyIndex], builderContext);
                // foreign is created, we will store it later if this assocation is registered too
                Expression thisKey = CreateColumn(tableExpression, theseKeys[keyIndex], builderContext);
                createdColumns.Add((ColumnExpression)thisKey);

                // if the key is nullable, then convert it
                // TODO: this will probably need to be changed
                if (otherKey.Type.IsNullable())
                {
                    otherKey = Expression.Convert(otherKey, otherKey.Type.GetNullableType());
                }
                if (thisKey.Type.IsNullable())
                {
                    thisKey = Expression.Convert(thisKey, thisKey.Type.GetNullableType());
                }
                // the other key is set as left operand, this must be this way
                // since some vendors (SQL Server) don't support the opposite
                var referenceExpression = Expression.Equal(otherKey, thisKey);

                // if we already have a join expression, then we have a double condition here, so "AND" it
                if (joinExpression != null)
                {
                    joinExpression = Expression.And(joinExpression, referenceExpression);
                }
                else
                {
                    joinExpression = referenceExpression;
                }
            }
            // we complete the table here, now that we have all join information
            otherTableExpression.Join(joinType, tableExpression, joinExpression);

            // our table is created, with the expressions
            // now check if we didn't register exactly the same
            var existingTable = (from t in builderContext.EnumerateScopeTables() where t.IsEqualTo(otherTableExpression) select t).SingleOrDefault();

            if (existingTable != null)
            {
                return(existingTable);
            }

            builderContext.CurrentSelect.Tables.Add(otherTableExpression);
            foreach (var createdColumn in createdColumns)
            {
                builderContext.CurrentSelect.Columns.Add(createdColumn);
            }
            return(otherTableExpression);
        }
 /// <summary>
 /// Creates a default TableExpression
 /// </summary>
 /// <param name="tableType"></param>
 /// <param name="builderContext"></param>
 /// <returns></returns>
 public virtual TableExpression CreateTable(Type tableType, BuilderContext builderContext)
 {
     return(new TableExpression(tableType, DataMapper.GetTableName(tableType, builderContext.QueryContext.DataContext)));
 }