public virtual IList<MemberInfo> GetPrimaryKeys(TableExpression tableExpression, DataContext dataContext) { var tableDescription = dataContext.Mapping.GetTable(tableExpression.Type); if (tableDescription != null) return GetPrimaryKeys(tableDescription); return null; }
public override bool IsEqualTo(TableExpression expression) { SubSelectExpression subSelectTable = expression as SubSelectExpression; if (subSelectTable == null) return false; return Name == expression.Name && JoinID == expression.JoinID && Select == subSelectTable.Select; }
/// <summary> /// Returns a registered column, or null if not found /// This method requires the table to be already registered /// </summary> /// <param name="table"></param> /// <param name="name"></param> /// <param name="builderContext"></param> /// <returns></returns> protected virtual ColumnExpression GetRegisteredColumn(TableExpression table, string name, BuilderContext builderContext) { return (from queryColumn in builderContext.EnumerateScopeColumns() where queryColumn.Table.IsEqualTo(table) && queryColumn.Name == name select queryColumn).SingleOrDefault(); }
public ColumnExpression(TableExpression table, string name, MemberInfo memberInfo) : base(ExpressionType, memberInfo.GetMemberType()) { Table = table; Name = name; MemberInfo = memberInfo; RequestIndex = -1; // unused }
public ColumnExpression(TableExpression table, MetaDataMember metaData) : base(ExpressionType, metaData.Member.GetMemberType()) // memberInfo.GetMemberType()) { Table = table; Name = metaData.MappedName; MemberInfo = metaData.Member; StorageInfo = metaData.StorageMember; RequestIndex = -1; // unused }
internal EntitySetExpression(TableExpression sourceTable, MemberInfo memberInfo, Type entitySetType, BuilderContext builderContext, ExpressionDispatcher dispatcher) : base(ExpressionType, entitySetType) { this.builderContext = builderContext; this.EntitySetType = entitySetType; this.dispatcher = dispatcher; this.sourceTable = sourceTable; this.memberInfo = memberInfo; ParseExpression(sourceTable); }
/// <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 the table as returned by the SQL request. /// Actually, the table is split into its columns. /// </summary> /// <param name="tableExpression"></param> /// <param name="dataRecordParameter"></param> /// <param name="mappingContextParameter"></param> /// <param name="builderContext"></param> /// <returns></returns> protected virtual Expression GetOutputTableReader(TableExpression tableExpression, ParameterExpression dataRecordParameter, ParameterExpression mappingContextParameter, BuilderContext builderContext) { var bindings = new List<MemberBinding>(); foreach (ColumnExpression columnExpression in RegisterAllColumns(tableExpression, builderContext)) { MemberInfo memberInfo = columnExpression.StorageInfo ?? columnExpression.MemberInfo; PropertyInfo propertyInfo = memberInfo as PropertyInfo; if (propertyInfo == null || propertyInfo.CanWrite) { var parameterColumn = GetOutputValueReader(columnExpression, dataRecordParameter, mappingContextParameter, builderContext); var binding = Expression.Bind(memberInfo, parameterColumn); bindings.Add(binding); } } var newExpression = Expression.New(tableExpression.Type); var initExpression = Expression.MemberInit(newExpression, bindings); return initExpression; }
/// <summary> /// Promotes a table to a common parent between its current scope and our current scope /// </summary> /// <param name="tableExpression"></param> /// <param name="builderContext"></param> /// <returns></returns> protected virtual TableExpression PromoteTable(TableExpression tableExpression, BuilderContext builderContext) { int currentIndex = 0; SelectExpression oldSelect = null; SelectExpression commonScope = null; TableExpression foundTable = null; do { // take a select oldSelect = builderContext.SelectExpressions[currentIndex]; // look for a common scope if (oldSelect != builderContext.CurrentSelect) { commonScope = FindCommonScope(oldSelect, builderContext.CurrentSelect); if (commonScope != null) // if a common scope exists, look for an equivalent table in that select for (int tableIndex = 0; tableIndex < oldSelect.Tables.Count && foundTable == null; tableIndex++) { if (oldSelect.Tables[tableIndex].IsEqualTo(tableExpression)) { // found a matching table! foundTable = oldSelect.Tables[tableIndex]; } } } ++currentIndex; } while (currentIndex < builderContext.SelectExpressions.Count && foundTable == null); if (foundTable != null) { oldSelect.Tables.Remove(foundTable); commonScope.Tables.Add(foundTable); } return foundTable; }
public virtual bool IsEqualTo(TableExpression expression) { return Name == expression.Name && JoinID == expression.JoinID; }
public virtual string GetColumnName(TableExpression tableExpression, MemberInfo memberInfo, DataContext dataContext) { return GetColumnName(tableExpression.Type, memberInfo, dataContext); }
public ColumnExpression CreateColumn(TableExpression table, MemberInfo memberInfo, BuilderContext builderContext) { var dataMember = builderContext.QueryContext.DataContext.Mapping.GetTable(table.Type).RowType .GetDataMember(memberInfo); if (dataMember == null) return null; return new ColumnExpression(table, dataMember.MappedName, memberInfo); }
/// <summary> /// Registers all columns of a table. /// </summary> /// <param name="tableExpression"></param> /// <param name="builderContext"></param> /// <returns></returns> public virtual IEnumerable<ColumnExpression> RegisterAllColumns(TableExpression tableExpression, BuilderContext builderContext) { foreach (var metaMember in builderContext.QueryContext.DataContext.Mapping.GetTable(tableExpression.Type).RowType.PersistentDataMembers) { yield return RegisterColumn(tableExpression, metaMember.Member, builderContext); } }
/// <summary> /// Set table join /// </summary> /// <param name="joinType"></param> /// <param name="joinedTable"></param> /// <param name="joinExpression"></param> public void Join(TableJoinType joinType, TableExpression joinedTable, Expression joinExpression) { JoinExpression = joinExpression; JoinType = joinType; JoinedTable = joinedTable; }
protected virtual SelectExpression FindTableScope(ref TableExpression tableExpression, BuilderContext builderContext) { foreach (var scope in builderContext.SelectExpressions) { for (int tableIndex = 0; tableIndex < scope.Tables.Count; tableIndex++) { if (scope.Tables[tableIndex].IsEqualTo(tableExpression)) { tableExpression = scope.Tables[tableIndex]; scope.Tables.RemoveAt(tableIndex); return scope; } } } return null; }
/// <summary> /// Replaces a table selection by a selection of all mapped columns (ColumnExpressions). /// ColumnExpressions will be replaced at a later time by the tier splitter /// </summary> /// <param name="tableExpression"></param> /// <param name="builderContext"></param> /// <returns></returns> protected virtual Expression GetSelectTableExpression(TableExpression tableExpression, BuilderContext builderContext) { var bindings = new List<MemberBinding>(); foreach (var columnExpression in RegisterAllColumns(tableExpression, builderContext)) { var binding = Expression.Bind((MethodInfo) columnExpression.MemberInfo, columnExpression); bindings.Add(binding); } var newExpression = Expression.New(tableExpression.Type); return Expression.MemberInit(newExpression, bindings); }
public override Expression Mutate(IList<Expression> newOperands) { if (newOperands.Count != 1) throw Error.BadArgument("S0063: Bad argument count"); TableExpression = (TableExpression)newOperands[0]; // ParseExpression(TableExpression); return this; }
protected virtual bool MustDeclareAsJoin(TableExpression table) { return false; }
/// <summary> /// Set table join /// </summary> /// <param name="joinType"></param> /// <param name="joinedTable"></param> /// <param name="joinExpression"></param> /// <param name="joinID"></param> public void Join(TableJoinType joinType, TableExpression joinedTable, Expression joinExpression, string joinID) { Join(joinType, joinedTable, joinExpression); JoinID = joinID; }
/// <summary> /// Returns association definition, if any /// </summary> /// <param name="thisTableExpression">The table referenced by the assocation (the type holding the member)</param> /// <param name="memberInfo">The memberInfo related to association</param> /// <param name="thisKey">The keys in the joined table</param> /// <param name="otherKey">The keys in the associated table</param> /// <param name="joinType"></param> /// <param name="joinID"></param> /// <param name="dataContext"></param> /// <returns></returns> public virtual Type GetAssociation(TableExpression thisTableExpression, MemberInfo memberInfo, out IList<MemberInfo> thisKey, out IList<MemberInfo> otherKey, out TableJoinType joinType, out string joinID, DataContext dataContext) { var thisTableDescription = dataContext.Mapping.GetTable(thisTableExpression.Type); var thisAssociation = (from association in thisTableDescription.RowType.Associations where association.ThisMember.Member == memberInfo select association).SingleOrDefault(); if (thisAssociation != null) { joinType = TableJoinType.Inner; joinID = thisAssociation.ThisMember.MappedName; if (string.IsNullOrEmpty(joinID)) throw Error.BadArgument("S0108: Association name is required to ensure join uniqueness"); var otherType = thisAssociation.ThisMember.Type; if (otherType.IsGenericType) // TODO: something serious here otherType = otherType.GetGenericArguments()[0]; var otherTableDescription = dataContext.Mapping.GetTable(otherType); thisKey = GetAssociationKeys(thisTableDescription, thisAssociation.ThisKey, dataContext); otherKey = GetAssociationKeys(otherTableDescription, thisAssociation.OtherKey, dataContext); return otherType; } thisKey = null; otherKey = null; joinType = TableJoinType.Default; joinID = null; return null; }
protected virtual bool MustDeclareAsJoin(IList<TableExpression> tables, TableExpression table) { // the first table can not be declared as join if (table == tables[0]) return false; // we must declare as join, whatever the join is, // if some of the registered tables are registered as complex join if (tables.Any(t => t.JoinType != TableJoinType.Inner)) return table.JoinExpression != null; return false; }
private void ParseExpression(TableExpression sourceTable) { // var sourceTable = targetTable.JoinedTable; var entityType = EntitySetType.GetGenericArguments()[0]; // BUG: This is ignoring External Mappings from XmlMappingSource. var mappingType = builderContext.QueryContext.DataContext.Mapping.GetMetaType(entityType); var foreignKeys = mappingType.Associations.Where(a => a.IsForeignKey && a.OtherType.Type == sourceTable.Type); foreach (var fk in foreignKeys) { var oke = fk.OtherKey.GetEnumerator(); var tke = fk.ThisKey.GetEnumerator(); bool ho, ht; while ((ho = oke.MoveNext()) && (ht = tke.MoveNext())) { var ok = oke.Current; var tk = tke.Current; var column = dispatcher.RegisterColumn(sourceTable, ok.Member, builderContext); Columns.Add(new KeyValuePair<ColumnExpression, MetaDataMember>(column, tk)); } } }
/// <summary> /// Promotes a table to a common parent between its current scope and our current scope /// </summary> /// <param name="tableExpression"></param> /// <param name="builderContext"></param> /// <returns></returns> protected virtual TableExpression PromoteTable(TableExpression tableExpression, BuilderContext builderContext) { // 1. Find the table ScopeExpression SelectExpression oldSelect = FindTableScope(ref tableExpression, builderContext); if (oldSelect == null) return null; // 2. Find a common ScopeExpression var commonScope = FindCommonScope(oldSelect, builderContext.CurrentSelect); commonScope.Tables.Add(tableExpression); return tableExpression; }
protected TableExpression(ExpressionType expressionType, TableExpression tableExpression) : base(expressionType, tableExpression.Type) { Name = tableExpression.Name; }
/// <summary> /// Registers a column /// This method requires the table to be already registered /// </summary> /// <param name="table"></param> /// <param name="memberInfo"></param> /// <param name="name"></param> /// <param name="builderContext"></param> /// <returns></returns> public ColumnExpression RegisterColumn(TableExpression table, MemberInfo memberInfo, string name, BuilderContext builderContext) { if (memberInfo == null) return null; var queryColumn = GetRegisteredColumn(table, name, builderContext); if (queryColumn == null) { table = RegisterTable(table, builderContext); queryColumn = CreateColumn(table, memberInfo, builderContext); builderContext.CurrentSelect.Columns.Add(queryColumn); } return queryColumn; }
/// <summary> /// Registers an association /// </summary> /// <param name="tableExpression">The table holding the member, to become the joinedTable</param> /// <param name="tableMemberInfo"></param> /// <param name="builderContext"></param> /// <returns></returns> public virtual TableExpression RegisterAssociation(TableExpression tableExpression, MemberInfo tableMemberInfo, BuilderContext builderContext) { IList<MemberInfo> theseKeys, otherKeys; TableJoinType joinType; string joinID; var otherTableType = DataMapper.GetAssociation(tableExpression, tableMemberInfo, out theseKeys, out otherKeys, out joinType, out joinID, builderContext.QueryContext.DataContext); // if the memberInfo has no corresponding association, we get a null, that we propagate if (otherTableType == 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(otherTableType, DataMapper.GetTableName(otherTableType, 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()); var referenceExpression = Expression.Equal(thisKey, otherKey); // 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; }
/// <summary> /// Registers the table as returned by the SQL request. /// Actually, the table is split into its columns. /// </summary> /// <param name="tableExpression"></param> /// <param name="dataRecordParameter"></param> /// <param name="mappingContextParameter"></param> /// <param name="builderContext"></param> /// <returns></returns> protected virtual Expression GetOutputTableReader(TableExpression tableExpression, ParameterExpression dataRecordParameter, ParameterExpression mappingContextParameter, BuilderContext builderContext) { var bindings = new List<MemberBinding>(); foreach (var columnExpression in RegisterAllColumns(tableExpression, builderContext)) { var parameterColumn = GetOutputValueReader(columnExpression, dataRecordParameter, mappingContextParameter, builderContext); var binding = Expression.Bind(columnExpression.MemberInfo, parameterColumn); bindings.Add(binding); } var newExpression = Expression.New(tableExpression.Type); var initExpression = Expression.MemberInit(newExpression, bindings); return initExpression; }
/// <summary> /// Returns association definition, if any /// </summary> /// <param name="thisTableExpression">The table referenced by the assocation (the type holding the member)</param> /// <param name="memberInfo">The memberInfo related to association</param> /// <param name="otherType"></param> /// <param name="otherKey">The keys in the associated table</param> /// <param name="joinType"></param> /// <param name="joinID"></param> /// <param name="dataContext"></param> /// <returns>ThisKey</returns> public virtual IList<MemberInfo> GetAssociation(TableExpression thisTableExpression, MemberInfo memberInfo, Type otherType, out IList<MemberInfo> otherKey, out TableJoinType joinType, out string joinID, DataContext dataContext) { var thisTableDescription = dataContext.Mapping.GetTable(thisTableExpression.Type); var thisAssociation = (from association in thisTableDescription.RowType.Associations where association.ThisMember.Member == memberInfo select association).SingleOrDefault(); if (thisAssociation != null) { // by default, join is inner joinType = TableJoinType.Inner; joinID = thisAssociation.ThisMember.MappedName; if (string.IsNullOrEmpty(joinID)) throw Error.BadArgument("S0108: Association name is required to ensure join uniqueness"); var otherTableDescription = dataContext.Mapping.GetTable(otherType); bool thisKeyHasNullables, otherKeyHasNullables; var thisKey = GetAssociationKeys(thisTableDescription, thisAssociation.ThisKey, dataContext, out thisKeyHasNullables); otherKey = GetAssociationKeys(otherTableDescription, thisAssociation.OtherKey, dataContext, out otherKeyHasNullables); // we just test here the left join (since associations are symmetric, // we can only find left joins here, and the otherKeyHasNullables is // always equal to thisKeyHasNullables) if (thisKeyHasNullables) joinType |= TableJoinType.LeftOuter; return thisKey; } otherKey = null; joinType = TableJoinType.Default; joinID = null; return null; }