public override Expression GetMemberExpression(Expression root, MappingEntity entity, MemberInfo member) { if (this.mapping.IsAssociationRelationship(entity, member)) { MappingEntity 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; } TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(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.Columns, projection.Select, where), pc.Projector, aggregator ); return(this.translator.Police.ApplyPolicy(result, member)); } else { AliasedExpression aliasedRoot = root as AliasedExpression; if (aliasedRoot != null && this.mapping.IsColumn(entity, member)) { return(new ColumnExpression(TypeHelper.GetMemberType(member), this.GetColumnType(entity, member), aliasedRoot.Alias, this.mapping.GetColumnName(entity, member))); } return(QueryBinder.BindMember(root, member)); } }
protected virtual Expression GetInsertResult(MappingEntity entity, Expression instance, LambdaExpression selector, Dictionary <MemberInfo, Expression> map) { var tableAlias = new TableAlias(); var tex = new TableExpression(tableAlias, 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 ColumnExpression(mex.Type, genIdCommand.Variables[0].QueryType, genIdCommand.Source.Alias, genIdCommand.Source.Columns[0].Name), aggregator )); } else { TableAlias alias = new TableAlias(); var colType = this.GetColumnType(entity, mex.Member); return(new ProjectionExpression( new SelectExpression(alias, new[] { new ColumnDeclaration("", map[mex.Member], colType) }, null, null), new ColumnExpression(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); TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(this.translator.Linguist.Language, 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); }
public override ProjectionExpression GetQueryExpression(MappingEntity entity) { var tables = this.mapping.GetTables(entity); if (tables.Count <= 1) { return(base.GetQueryExpression(entity)); } var aliases = new Dictionary <string, TableAlias>(); MappingTable rootTable = tables.Single(ta => !this.mapping.IsExtensionTable(ta)); var tex = new TableExpression(new TableAlias(), entity, this.mapping.GetTableName(rootTable)); aliases.Add(this.mapping.GetTableId(rootTable), tex.Alias); Expression source = tex; foreach (MappingTable table in tables.Where(t => this.mapping.IsExtensionTable(t))) { TableAlias joinedTableAlias = new TableAlias(); string extensionAlias = this.mapping.GetTableId(table); aliases.Add(extensionAlias, joinedTableAlias); List <string> keyColumns = this.mapping.GetExtensionKeyColumnNames(table).ToList(); List <MemberInfo> relatedMembers = this.mapping.GetExtensionRelatedMembers(table).ToList(); string relatedAlias = this.mapping.GetExtensionRelatedTableId(table); TableAlias relatedTableAlias; aliases.TryGetValue(relatedAlias, out relatedTableAlias); TableExpression joinedTex = new TableExpression(joinedTableAlias, entity, this.mapping.GetTableName(table)); Expression cond = null; for (int i = 0, n = keyColumns.Count; i < n; i++) { var memberType = TypeHelper.GetMemberType(relatedMembers[i]); var colType = this.GetColumnType(entity, relatedMembers[i]); var relatedColumn = new ColumnExpression(memberType, colType, relatedTableAlias, this.mapping.GetColumnName(entity, relatedMembers[i])); var joinedColumn = new ColumnExpression(memberType, colType, joinedTableAlias, keyColumns[i]); var eq = joinedColumn.Equal(relatedColumn); cond = (cond != null) ? cond.And(eq) : eq; } source = new JoinExpression(JoinType.SingletonLeftOuter, source, joinedTex, cond); } var columns = new List <ColumnDeclaration>(); this.GetColumns(entity, aliases, columns); SelectExpression root = new SelectExpression(new TableAlias(), columns, source, null); var existingAliases = aliases.Values.ToArray(); Expression projector = this.GetEntityExpression(root, entity); var selectAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(this.Translator.Linguist.Language, projector, null, selectAlias, root.Alias); var proj = new ProjectionExpression( new SelectExpression(selectAlias, pc.Columns, root, null), pc.Projector ); return((ProjectionExpression)this.Translator.Police.ApplyPolicy(proj, entity.StaticType.GetTypeInfo())); }
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; } }