示例#1
0
        /// <summary>
        /// Returns an existing table or registers the current one
        /// </summary>
        /// <param name="tableExpression"></param>
        /// <param name="builderContext"></param>
        /// <returns>A registered table or the current newly registered one</returns>
        public virtual TableExpression RegisterTable(TableExpression tableExpression, BuilderContext builderContext)
        {
            // 1. Find the table in current scope
            var foundTableExpression = (from t in builderContext.EnumerateScopeTables()
                                        where t.IsEqualTo(tableExpression)
                                        select t).SingleOrDefault();

            if (foundTableExpression != null)
            {
                return(foundTableExpression);
            }
            // 2. Find it in all scopes, and promote it to current scope.
            foundTableExpression = PromoteTable(tableExpression, builderContext);
            if (foundTableExpression != null)
            {
                return(foundTableExpression);
            }
            // 3. Add it
            builderContext.CurrentSelect.Tables.Add(tableExpression);
            return(tableExpression);
        }
示例#2
0
        /// <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
            if ((from t in builderContext.EnumerateScopeTables() where t.IsEqualTo(otherTableExpression) select t).SingleOrDefault() == null)
            {
                builderContext.CurrentSelect.Tables.Add(otherTableExpression);
                foreach (var createdColumn in createdColumns)
                {
                    builderContext.CurrentSelect.Columns.Add(createdColumn);
                }
            }

            return(otherTableExpression);
        }