/// <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); }
/// <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); }