public ClientJoinExpression(ProjectionExpression projection, IEnumerable<Expression> outerKey, IEnumerable<Expression> innerKey) : base(DbExpressionType.ClientJoin, projection.Type) { this.outerKey = outerKey.ToReadOnly(); this.innerKey = innerKey.ToReadOnly(); this.projection = projection; }
public OUpdateCommandExpression(IdentifiableExpression identifiable, Expression where, IEnumerable<FieldAssignment> assignments, Expression projector) : base(identifiable, where, assignments) { Projection = new ProjectionExpression(null, projector, Aggregator.GetAggregator(projector.Type, typeof(IEnumerable<>).MakeGenericType(projector.Type))); }
public virtual ProjectionExpression AddOuterJoinTest(ProjectionExpression proj) { var test = this.GetOuterJoinTest(proj.Select); var select = proj.Select; FieldExpression testCol = null; // look to see if test expression exists in fields already foreach (var col in select.Fields) { if (test.Equals(col.Expression)) { var colType = this.TypeSystem.GetStorageType(test.Type); testCol = new FieldExpression(test.Type, colType, select.Alias, col.Name); break; } } if (testCol == null) { // add expression to projection testCol = test as FieldExpression; string colName = (testCol != null) ? testCol.Name : "Test"; colName = proj.Select.Fields.GetAvailableFieldName(colName); var colType = this.TypeSystem.GetStorageType(test.Type); select = select.AddField(new FieldDeclaration(colName, test, colType)); testCol = new FieldExpression(test.Type, colType, select.Alias, colName); } var newProjector = new OuterJoinedExpression(testCol, proj.Projector); return new ProjectionExpression(select, newProjector, proj.Aggregator); }
protected ClientJoinExpression UpdateClientJoin(ClientJoinExpression join, ProjectionExpression projection, IEnumerable<Expression> outerKey, IEnumerable<Expression> innerKey) { if (projection != join.Projection || outerKey != join.OuterKey || innerKey != join.InnerKey) { return new ClientJoinExpression(projection, outerKey, innerKey); } return join; }
protected virtual UpdateCommandExpression UpdateUpdate(OUpdateCommandExpression update, IdentifiableExpression table, Expression where, IEnumerable<FieldAssignment> assignments, ProjectionExpression projection) { if (table != update.Identifiable || where != update.Where || assignments != update.Assignments || projection.Projector != update.Projection.Projector) { return new OUpdateCommandExpression(table, where, assignments, projection.Projector); } return update; }
protected virtual InsertCommandExpression UpdateInsert(OInsertCommandExpression insert, IdentifiableExpression table, IEnumerable<FieldAssignment> assignments, ProjectionExpression projection) { if (table != insert.Identifiable || assignments != insert.Assignments || projection.Projector != insert.Projection.Projector) { return new OInsertCommandExpression(table, assignments, projection.Projector); } return insert; }
protected override Expression VisitProjection(ProjectionExpression proj) { proj = (ProjectionExpression)base.VisitProjection(proj); if (proj.Select.From is SelectExpression) { List<SelectExpression> redundant = RedundantSubqueryGatherer.Gather(proj.Select); if (redundant != null) { proj = SubqueryRemover.Remove(proj, redundant); } } return proj; }
protected override Expression VisitProjection(ProjectionExpression proj) { if (isTopLevel) { isTopLevel = false; this.currentSelect = proj.Select; Expression projector = this.Visit(proj.Projector); if (projector != proj.Projector || this.currentSelect != proj.Select) { return new ProjectionExpression(this.currentSelect, projector, proj.Aggregator); } return proj; } if (proj.IsSingleton && this.CanJoinOnServer(this.currentSelect)) { IdentifiableAlias newAlias = new IdentifiableAlias(); this.currentSelect = this.currentSelect.AddRedundantSelect(this.language, newAlias); // remap any references to the outer select to the new alias; SelectExpression source = (SelectExpression)FieldMapper.Map(proj.Select, newAlias, this.currentSelect.Alias); // add outer-join test ProjectionExpression pex = this.language.AddOuterJoinTest(new ProjectionExpression(source, proj.Projector)); var pc = FieldProjector.ProjectFields(this.language, pex.Projector, this.currentSelect.Fields, this.currentSelect.Alias, newAlias, proj.Select.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, this.currentSelect.From, pex.Select, null); this.currentSelect = new SelectExpression(this.currentSelect.Alias, pc.Fields, join, null); return this.Visit(pc.Projector); } var saveTop = this.isTopLevel; var saveSelect = this.currentSelect; this.isTopLevel = true; this.currentSelect = null; Expression result = base.VisitProjection(proj); this.isTopLevel = saveTop; this.currentSelect = saveSelect; return result; }
protected ProjectionExpression UpdateProjection(ProjectionExpression proj, SelectExpression select, Expression projector, LambdaExpression aggregator) { if (select != proj.Select || projector != proj.Projector || aggregator != proj.Aggregator) { return new ProjectionExpression(select, projector, aggregator); } return proj; }
public static ProjectionExpression Remove(ProjectionExpression projection, IEnumerable<SelectExpression> selectsToRemove) { return (ProjectionExpression)new OSubqueryRemover(selectsToRemove).Visit(projection); }
public static ProjectionExpression Remove(ProjectionExpression projection, params SelectExpression[] selectsToRemove) { return Remove(projection, (IEnumerable<SelectExpression>)selectsToRemove); }
protected override Expression VisitProjection(ProjectionExpression proj) { Expression projector = this.Visit(proj.Projector); return this.UpdateProjection(proj, proj.Select, projector, proj.Aggregator); }
protected virtual bool CompareProjection(ProjectionExpression a, ProjectionExpression b) { if (!this.Compare(a.Select, b.Select)) return false; var save = this.aliasScope; try { this.aliasScope = new ScopedDictionary<IdentifiableAlias, IdentifiableAlias>(this.aliasScope); this.aliasScope.Add(a.Select.Alias, b.Select.Alias); return this.Compare(a.Projector, b.Projector) && this.Compare(a.Aggregator, b.Aggregator) && a.IsSingleton == b.IsSingleton; } finally { this.aliasScope = save; } }
public override ProjectionExpression GetQueryExpression(IMappedEntity entity) { var IdentifiableAlias = new IdentifiableAlias(); var selectAlias = new IdentifiableAlias(); var table = new IdentifiableExpression(IdentifiableAlias, entity, this.mapping.GetTableName(entity)); Expression projector = this.GetEntityExpression(table, entity); var pc = FieldProjector.ProjectFields(this.translator.Linguist.Language, projector, null, selectAlias, IdentifiableAlias); var proj = new ProjectionExpression( new SelectExpression(selectAlias, pc.Fields, table, null), pc.Projector ); return (ProjectionExpression)this.Translator.Police.ApplyPolicy(proj, entity.EntityType); }
protected override Expression VisitProjection(ProjectionExpression projection) { // visit mapping in reverse order Expression projector = this.Visit(projection.Projector); SelectExpression select = (SelectExpression)this.Visit(projection.Select); return this.UpdateProjection(projection, select, projector, projection.Aggregator); }
protected override Expression VisitProjection(ProjectionExpression proj) { this.Visit(proj.Projector); return proj; }
protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector) { ProjectionExpression projection = this.VisitSequence(source); this.map[keySelector.Parameters[0]] = projection.Projector; Expression keyExpr = this.Visit(keySelector.Body); Expression elemExpr = projection.Projector; if (elementSelector != null) { this.map[elementSelector.Parameters[0]] = projection.Projector; elemExpr = this.Visit(elementSelector.Body); } // Use ProjectFields to get group-by expressions from key expression ProjectedFields keyProjection = this.ProjectFields(keyExpr, projection.Select.Alias, projection.Select.Alias); var groupExprs = keyProjection.Fields.Select(c => c.Expression).ToArray(); // make duplicate of source query as basis of element subquery by visiting the source again ProjectionExpression subqueryBasis = this.VisitSequence(source); // recompute key fields for group expressions relative to subquery (need these for doing the correlation predicate) this.map[keySelector.Parameters[0]] = subqueryBasis.Projector; Expression subqueryKey = this.Visit(keySelector.Body); // use same projection trick to get group-by expressions based on subquery ProjectedFields subqueryKeyPC = this.ProjectFields(subqueryKey, subqueryBasis.Select.Alias, subqueryBasis.Select.Alias); var subqueryGroupExprs = subqueryKeyPC.Fields.Select(c => c.Expression).ToArray(); Expression subqueryCorrelation = this.BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs); // compute element based on duplicated subquery Expression subqueryElemExpr = subqueryBasis.Projector; if (elementSelector != null) { this.map[elementSelector.Parameters[0]] = subqueryBasis.Projector; subqueryElemExpr = this.Visit(elementSelector.Body); } // build subquery that projects the desired element var elementAlias = this.GetNextAlias(); ProjectedFields elementPC = this.ProjectFields(subqueryElemExpr, elementAlias, subqueryBasis.Select.Alias); ProjectionExpression elementSubquery = new ProjectionExpression( new SelectExpression(elementAlias, elementPC.Fields, subqueryBasis.Select, subqueryCorrelation), elementPC.Projector ); var alias = this.GetNextAlias(); // make it possible to tie aggregates back to this group-by GroupByInfo info = new GroupByInfo(alias, elemExpr); this.groupByMap.Add(elementSubquery, info); Expression resultExpr; if (resultSelector != null) { Expression saveGroupElement = this.currentGroupElement; this.currentGroupElement = elementSubquery; // compute result expression based on key & element-subquery this.map[resultSelector.Parameters[0]] = keyProjection.Projector; this.map[resultSelector.Parameters[1]] = elementSubquery; resultExpr = this.Visit(resultSelector.Body); this.currentGroupElement = saveGroupElement; } else { // result must be IGrouping<K,E> resultExpr = Expression.New( typeof(Grouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0], new Expression[] { keyExpr, elementSubquery } ); resultExpr = Expression.Convert(resultExpr, typeof(IGrouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type)); } ProjectedFields pc = this.ProjectFields(resultExpr, alias, projection.Select.Alias); // make it possible to tie aggregates back to this group-by NewExpression newResult = this.GetNewExpression(pc.Projector); if (newResult != null && newResult.Type.IsGenericType && newResult.Type.GetGenericTypeDefinition() == typeof(Grouping<,>)) { Expression projectedElementSubquery = newResult.Arguments[1]; this.groupByMap.Add(projectedElementSubquery, info); } return new ProjectionExpression( new SelectExpression(alias, pc.Fields, projection.Select, null, null, groupExprs), pc.Projector ); }
protected override Expression VisitProjection(ProjectionExpression proj) { SelectExpression save = this.currentSelect; this.currentSelect = proj.Select; try { if (!this.isTopLevel) { if (this.CanJoinOnClient(this.currentSelect)) { // make a query that combines all the constraints from the outer queries into a single select SelectExpression newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save); // remap any references to the outer select to the new alias; SelectExpression newInnerSelect = (SelectExpression)FieldMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias); // add outer-join test ProjectionExpression newInnerProjection = this.language.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector)); newInnerSelect = newInnerProjection.Select; Expression newProjector = newInnerProjection.Projector; IdentifiableAlias newAlias = new IdentifiableAlias(); var pc = FieldProjector.ProjectFields(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Fields, join, null, null, null, proj.IsSingleton, null, null, false); // apply client-join treatment recursively this.currentSelect = joinedSelect; newProjector = this.Visit(pc.Projector); // compute keys (this only works if join condition was a single field comparison) List<Expression> outerKeys = new List<Expression>(); List<Expression> innerKeys = new List<Expression>(); if (this.GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys)) { // outerKey needs to refer to the outer-scope's alias var outerKey = outerKeys.Select(k => FieldMapper.Map(k, save.Alias, newOuterSelect.Alias)); // innerKey needs to refer to the new alias for the select with the new join var innerKey = innerKeys.Select(k => FieldMapper.Map(k, joinedSelect.Alias, ((FieldExpression)k).Alias)); ProjectionExpression newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator); return new ClientJoinExpression(newProjection, outerKey, innerKey); } } else { bool saveJoin = this.canJoinOnClient; this.canJoinOnClient = false; var result = base.VisitProjection(proj); this.canJoinOnClient = saveJoin; return result; } } else { this.isTopLevel = false; } return base.VisitProjection(proj); } finally { this.currentSelect = save; } }
protected override Expression VisitProjection(ProjectionExpression proj) { // treat these like scalar subqueries if ((proj.Projector is FieldExpression) || this.forDebug) { this.Write("("); this.WriteLine(Indentation.Inner); this.Visit(proj.Select); this.Write(")"); this.Indent(Indentation.Outer); } else { throw new NotSupportedException("Non-scalar projections cannot be translated to SQL."); } return proj; }
protected virtual Expression VisitProjection(ProjectionExpression proj) { var select = (SelectExpression)this.Visit(proj.Select); var projector = this.Visit(proj.Projector); return this.UpdateProjection(proj, select, projector, proj.Aggregator); }
protected virtual Expression GetInsertResult(IMappedEntity entity, Expression instance, LambdaExpression selector, Dictionary<MemberInfo, Expression> map) { var IdentifiableAlias = new IdentifiableAlias(); var tex = new IdentifiableExpression(IdentifiableAlias, entity, this.mapping.GetTableName(entity)); var aggregator = Aggregator.GetAggregator(selector.Body.Type, typeof(IEnumerable<>).MakeGenericType(selector.Body.Type)); Expression where; DeclarationCommand genIdCommand = null; var generatedIds = this.mapping.GetMappedMembers(entity).Where(m => this.mapping.IsPrimaryKey(entity, m) && this.mapping.IsGenerated(entity, m)).ToList(); if (generatedIds.Count > 0) { if (map == null || !generatedIds.Any(m => map.ContainsKey(m))) { var localMap = new Dictionary<MemberInfo, Expression>(); genIdCommand = this.GetGeneratedIdCommand(entity, generatedIds.ToList(), localMap); map = localMap; } // is this just a retrieval of one generated id member? var mex = selector.Body as MemberExpression; if (mex != null && this.mapping.IsPrimaryKey(entity, mex.Member) && this.mapping.IsGenerated(entity, mex.Member)) { if (genIdCommand != null) { // just use the select from the genIdCommand return new ProjectionExpression( genIdCommand.Source, new FieldExpression(mex.Type, genIdCommand.Variables[0].QueryType, genIdCommand.Source.Alias, genIdCommand.Source.Fields[0].Name), aggregator ); } else { IdentifiableAlias alias = new IdentifiableAlias(); var colType = this.GetFieldType(entity, mex.Member); return new ProjectionExpression( new SelectExpression(alias, new[] { new FieldDeclaration("", map[mex.Member], colType) }, null, null), new FieldExpression(TypeHelper.GetMemberType(mex.Member), colType, alias, ""), aggregator ); } } where = generatedIds.Select((m, i) => this.GetMemberExpression(tex, entity, m).Equal(map[m]) ).Aggregate((x, y) => x.And(y)); } else { where = this.GetIdentityCheck(tex, entity, instance); } Expression typeProjector = this.GetEntityExpression(tex, entity); Expression selection = DbExpressionReplacer.Replace(selector.Body, selector.Parameters[0], typeProjector); IdentifiableAlias newAlias = new IdentifiableAlias(); var pc = FieldProjector.ProjectFields(this.translator.Linguist.Language, selection, null, newAlias, IdentifiableAlias); var pe = new ProjectionExpression( new SelectExpression(newAlias, pc.Fields, tex, where), pc.Projector, aggregator ); if (genIdCommand != null) { return new BlockCommandExpression(genIdCommand, pe); } return pe; }
protected virtual Expression VisitProjection(ProjectionExpression projection) { this.AddAlias(projection.Select.Alias); this.Write("Project("); this.WriteLine(Indentation.Inner); this.Write("@\""); this.Visit(projection.Select); this.Write("\","); this.WriteLine(Indentation.Same); this.Visit(projection.Projector); this.Write(","); this.WriteLine(Indentation.Same); this.Visit(projection.Aggregator); this.WriteLine(Indentation.Outer); this.Write(")"); return projection; }
private Expression BindFirst(Expression source, LambdaExpression predicate, string kind, bool isRoot) { ProjectionExpression projection = this.VisitSequence(source); Expression where = null; if (predicate != null) { this.map[predicate.Parameters[0]] = projection.Projector; where = this.Visit(predicate.Body); } bool isFirst = kind.StartsWith("First"); bool isLast = kind.StartsWith("Last"); Expression take = (isFirst || isLast) ? Expression.Constant(1) : null; if (take != null || where != null) { var alias = this.GetNextAlias(); ProjectedFields pc = this.ProjectFields(projection.Projector, alias, projection.Select.Alias); projection = new ProjectionExpression( new SelectExpression(alias, pc.Fields, projection.Select, where, null, null, false, null, take, isLast), pc.Projector ); } if (isRoot) { Type elementType = projection.Projector.Type; ParameterExpression p = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(elementType), "p"); LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), kind, new Type[] { elementType }, p), p); return new ProjectionExpression(projection.Select, projection.Projector, gator); } return projection; }
public override Expression GetMemberExpression(Expression root, IMappedEntity entity, MemberInfo member) { if (this.mapping.IsAssociationRelationship(entity, member)) { var relatedEntity = this.mapping.GetRelatedEntity(entity, member); ProjectionExpression projection = this.GetQueryExpression(relatedEntity); // make where clause for joining back to 'root' var declaredTypeMembers = this.mapping.GetAssociationKeyMembers(entity, member).ToList(); var associatedMembers = this.mapping.GetAssociationRelatedKeyMembers(entity, member).ToList(); Expression where = null; for (int i = 0, n = associatedMembers.Count; i < n; i++) { Expression equal = this.GetMemberExpression(projection.Projector, relatedEntity, associatedMembers[i]).Equal( this.GetMemberExpression(root, entity, declaredTypeMembers[i]) ); where = (where != null) ? where.And(equal) : equal; } IdentifiableAlias newAlias = new IdentifiableAlias(); var pc = FieldProjector.ProjectFields(this.translator.Linguist.Language, projection.Projector, null, newAlias, projection.Select.Alias); LambdaExpression aggregator = Aggregator.GetAggregator(TypeHelper.GetMemberType(member), typeof(IEnumerable<>).MakeGenericType(pc.Projector.Type)); var result = new ProjectionExpression( new SelectExpression(newAlias, pc.Fields, projection.Select, where), pc.Projector, aggregator ); return this.translator.Police.ApplyPolicy(result, member); } else { AliasedExpression aliasedRoot = root as AliasedExpression; if (aliasedRoot != null && this.mapping.IsField(entity, member)) { return new FieldExpression(TypeHelper.GetMemberType(member), this.GetFieldType(entity, member), aliasedRoot.Alias, this.mapping.GetFieldName(entity, member)); } return QueryBinder.BindMember(root, member); } }
protected override Expression ExecuteProjection(ProjectionExpression projection, QueryCommand command, Expression[] values) { var saveScope = this.Scope; ParameterExpression reader = Expression.Parameter(typeof(FieldReader), "r" + nReaders++); this.Scope = new BuilderScope(this.Scope, reader, projection.Select.Alias, projection.Select.Fields) { UseOrdinalMapping = false // orient cannot guarantee ordinally mapped results - must map by name }; var projector = RedirectProjector(projection.Projector, reader, true); this.Scope = saveScope; var entity = EntityFinder.Find(projection.Projector); if (entity != null && entity.EntityType == typeof(_Thing)) { entity = new OMappingEntity(typeof(IIdentifiable),_repoType); } string methExecute = "Execute"; // call low-level execute directly on supplied DbQueryProvider Expression result = Expression.Call(this.Executor, methExecute, new Type[] { projector.Body.Type }, Expression.Constant(command), projector, Expression.Constant(entity, typeof(MappingEntity)), Expression.NewArrayInit(typeof(object), values) ); if (projection.Aggregator != null) { if (projector.ReturnType != projection.Aggregator.Parameters[0].Type.GetGenericArguments()[0]) { // we probably swaped out an Identifiable type for IIdentifiable, so we need to rebuild the projection // using the interface, otherwise we'll get cast failures downstream projection = new ProjectionExpression( projection.Select, projector, Aggregator.GetAggregator(projector.ReturnType, projection.Aggregator.Parameters[0].Type.GetGenericTypeDefinition().MakeGenericType(projector.ReturnType))); } // apply aggregator result = DbExpressionReplacer.Replace(projection.Aggregator.Body, projection.Aggregator.Parameters[0], result); } return result; }