protected override Expression VisitJoin(SqlJoinExpression join) { join = (SqlJoinExpression)base.VisitJoin(join); if (join.JoinType == SqlJoinType.CrossApply || join.JoinType == SqlJoinType.OuterApply) { if (join.Right is SqlTableExpression) { return(new SqlJoinExpression(join.Type, SqlJoinType.Cross, join.Left, join.Right, null)); } else { if (@join.Right is SqlSelectExpression @select && select.Take == null && select.Skip == null && !SqlAggregateChecker.HasAggregates(select) && (select.GroupBy == null || select.GroupBy.Count == 0)) { var selectWithoutWhere = select.ChangeWhere(null); var referencedAliases = SqlReferencedAliasGatherer.Gather(selectWithoutWhere); var declaredAliases = SqlDeclaredAliasGatherer.Gather(join.Left); referencedAliases.IntersectWith(declaredAliases); if (referencedAliases.Count == 0) { var where = select.Where; select = selectWithoutWhere; var pc = ColumnProjector.ProjectColumns(new Nominator(Nominator.CanBeColumn), where, select.Columns, select.Alias, SqlDeclaredAliasGatherer.Gather(select.From)); select = select.ChangeColumns(pc.Columns); where = pc.Projector; var joinType = (where == null) ? SqlJoinType.Cross : (join.JoinType == SqlJoinType.CrossApply ? SqlJoinType.Inner : SqlJoinType.Left); return(new SqlJoinExpression(typeof(void), joinType, join.Left, select, where)); } } } } return(join); }
public virtual ProjectionExpression GetQueryExpression(IEntityMapping mapping) { Expression projector; TableAlias selectAlias; ProjectedColumns pc; ProjectionExpression proj; var tableAlias = new TableAlias(); selectAlias = new TableAlias(); var table = new TableExpression(tableAlias, mapping); projector = this.GetEntityExpression(table, mapping); pc = ColumnProjector.ProjectColumns(projector, null, selectAlias, tableAlias); proj = new ProjectionExpression( new SelectExpression(selectAlias, pc.Columns, table, null), pc.Projector ); return((ProjectionExpression)ApplyPolicy(proj, mapping.EntityType)); }
protected internal override Expression VisitProjection(ProjectionExpression proj) { Expression projector; SelectExpression select = proj.Select; using (binder.SetCurrentSource(proj.Select)) projector = this.Visit(proj.Projector); Alias alias = binder.aliasGenerator.NextSelectAlias(); ProjectedColumns pc = ColumnProjector.ProjectColumns(projector, alias); projector = pc.Projector; select = new SelectExpression(alias, false, null, pc.Columns, select, null, null, null, 0); if (projector != proj.Projector) { return(new ProjectionExpression(select, projector, proj.UniqueFunction, proj.Type)); } return(proj); }
public virtual Expression GetInsertResult(IEntityMapping mapping, Expression instance, LambdaExpression selector, Dictionary <MemberInfo, Expression> map) { var tableAlias = new TableAlias(); var tex = new TableExpression(tableAlias, mapping); var aggregator = Aggregator.GetAggregator(selector.Body.Type, typeof(IEnumerable <>).MakeGenericType(selector.Body.Type)); Expression where = null; DeclarationCommand genIdCommand = null; var generatedIds = mapping.PrimaryKeys.Where(m => m.IsPrimaryKey && m.IsGenerated).ToList(); if (generatedIds.Count > 0) { if (map == null || !generatedIds.Any(m => map.ContainsKey(m.Member))) { var localMap = new Dictionary <MemberInfo, Expression>(); genIdCommand = this.GetGeneratedIdCommand(mapping, generatedIds, localMap); map = localMap; } // is this just a retrieval of one generated id member? var mex = selector.Body as MemberExpression; if (mex != null) { var id = mapping.Get(mex.Member); if (id != null && id.IsPrimaryKey && id.IsGenerated) { if (genIdCommand != null) { // just use the select from the genIdCommand return(new ProjectionExpression( genIdCommand.Source, new ColumnExpression(mex.Type, genIdCommand.Variables[0].SqlType, genIdCommand.Source.Alias, genIdCommand.Source.Columns[0].Name), aggregator )); } else { TableAlias alias = new TableAlias(); var colType = id.SqlType; return(new ProjectionExpression( new SelectExpression(alias, new[] { new ColumnDeclaration("", map[mex.Member], colType) }, null, null), new ColumnExpression(mex.Member.GetMemberType(), colType, alias, ""), aggregator )); } } where = generatedIds.Select((m, i) => this.GetMemberExpression(tex, mapping, m.Member).Equal(map[m.Member]) ).Aggregate((x, y) => x.And(y)); } } else { where = this.GetIdentityCheck(tex, mapping, instance); } Expression typeProjector = this.GetEntityExpression(tex, mapping); Expression selection = DbExpressionReplacer.Replace(selector.Body, selector.Parameters[0], typeProjector); TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(selection, null, newAlias, tableAlias); var pe = new ProjectionExpression( new SelectExpression(newAlias, pc.Columns, tex, where), pc.Projector, aggregator ); if (genIdCommand != null) { return(new BlockCommand(genIdCommand, pe)); } return(pe); }
/// <summary> /// Get an expression for a mapped property relative to a root expression. /// The root is either a TableExpression or an expression defining an entity instance. /// </summary> /// <param name="root"></param> /// <param name="member"></param> /// <returns></returns> public virtual Expression GetMemberExpression(Expression root, MemberInfo member) { if (IsRelationship(member)) { Type rowType = GetRelatedType(member); ProjectionExpression projection = GetTableQuery(rowType); // make where clause for joining back to 'root' List <MemberInfo> declaredTypeMembers; List <MemberInfo> associatedMembers; GetAssociationKeys(member, out declaredTypeMembers, out associatedMembers); Expression where = null; for (int i = 0, n = associatedMembers.Count; i < n; i++) { Expression equal = Expression.Equal( GetMemberExpression(projection.Projector, associatedMembers[i]), GetMemberExpression(root, declaredTypeMembers[i]) ); where = (where != null) ? Expression.And(where, equal) : equal; } TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(this.Language.CanBeColumn, projection.Projector, null, newAlias, projection.Source.Alias); LambdaExpression aggregator = GetAggregator(TypeHelper.GetMemberType(member), typeof(IEnumerable <>).MakeGenericType( pc.Projector.Type)); return(new ProjectionExpression( new SelectExpression(newAlias, pc.Columns, projection.Source, where), pc.Projector, aggregator )); } var tableExpression = root as TableExpression; if (tableExpression != null) { if (IsColumn(member)) { IColumn column = null; if (tableExpression.Table != null) { column = tableExpression.Table.GetColumnByPropertyName(member.Name); } var columnName = column != null?GetColumnName(column) : GetColumnName(member); return(!string.IsNullOrEmpty(columnName) ? new ColumnExpression(column, TypeHelper.GetMemberType(member), tableExpression.Alias, columnName) : root); } return(this.GetTypeProjection(root, TypeHelper.GetMemberType(member))); } return(QueryBinder.BindMember(root, member)); }
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)ColumnMapper.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; TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Columns, 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 column 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 => ColumnMapper.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 => ColumnMapper.Map(k, joinedSelect.Alias, ((ColumnExpression)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; } }