public override Identifier Visit(EntityIdentifier identifier) { if (visitingColumns) { currentAlias = identifier.Entity.Alias; return identifier; } return base.Visit(identifier); }
public virtual Evaluant.NLinq.Expressions.Identifier Update(EntityIdentifier entityIdentifier, EntityExpression entity, Evaluant.NLinq.Expressions.Identifier identifier) { if (entityIdentifier.Entity != entity || entityIdentifier.Identifier != identifier) return new EntityIdentifier(identifier, entity); return entityIdentifier; }
public override Evaluant.NLinq.Expressions.Expression Visit(Evaluant.NLinq.Expressions.MemberExpression expression) { if (getAlias) { if (expression.Previous is EntityIdentifier) { EntityIdentifier identifier = (EntityIdentifier)expression.Previous; if (!entityIdentifierAliases.ContainsKey(identifier.Text)) entityIdentifierAliases.Add(identifier.Text, identifier.Entity.Alias); return identifier; } if (expression.Previous != null) return Visit(expression.Previous); return base.Visit(expression); } if (getPreviousType) { if (expression.Previous is EntityIdentifier) return ((EntityIdentifier)expression.Previous).Entity; if (expression.Previous != null) { EntityExpression entity = (EntityExpression)Visit(expression.Previous); Model.Reference reference = engine.Factory.Model.Entities[entity.Type].References[((Evaluant.NLinq.Expressions.Identifier)expression.Statement).Text]; entity = new EntityExpression(new TableAlias()) { Type = reference.ChildType, Expression = expression }; return entity; } } if (expression.Statement.ExpressionType == NLinq.Expressions.ExpressionTypes.Call) { NLinq.Expressions.MethodCall item = (NLinq.Expressions.MethodCall)expression.Statement; AggregateFunctionType aggregateType; switch (item.Identifier.Text) { case "Count": aggregateType = AggregateFunctionType.Count; break; case "Average": aggregateType = AggregateFunctionType.Avg; break; case "Max": aggregateType = AggregateFunctionType.Max; break; case "Min": aggregateType = AggregateFunctionType.Min; break; case "Sum": aggregateType = AggregateFunctionType.Sum; break; default: aggregateType = AggregateFunctionType.Unknown; break; } if (aggregateType == AggregateFunctionType.Unknown) { SelectStatement oldSelect = select; if (item.Identifier.Text == "Take") { Visit(expression.Previous); select.Top = (int)((Constant)item.Parameters[0]).Value; return select; } if (item.Identifier.Text == "Skip") { Visit(expression.Previous); if (Convert.ToInt32(((Constant)item.Parameters[0]).Value) == 0) return select; if (select.OrderBy == null) throw new NotSupportedException("A skip operation cannot be done on a statement which is not ordered"); List<IAliasedExpression> columns = new List<IAliasedExpression>(select.Columns); columns.Add(new ComplexColumnExpression(null, new RowNumber(select.OrderBy), "rn" + select.Alias)); select.Columns = columns.ToArray(); columns.RemoveAt(columns.Count - 1); oldSelect = select; select = new SelectStatement(new TableAlias(), null, new FromClause(select), null, new NLinq.Expressions.WhereClause(new NLinq.Expressions.BinaryExpression(NLinq.Expressions.BinaryExpressionType.Greater, new ColumnExpression(select.Alias, "rn" + select.Alias), item.Parameters[0]))); columns = new List<IAliasedExpression>(); foreach (IAliasedExpression expr in oldSelect.Columns) { IAliasedExpression column = null; if (expr.DbExpressionType == DbExpressionType.Column) { column = new ColumnExpression(oldSelect.Alias, ((ColumnExpression)expr).ColumnAlias, ((ColumnExpression)expr).ColumnAlias); } else if (expr.DbExpressionType == DbExpressionType.Entity) { EntityExpression entity = expr as EntityExpression; column = new ComplexColumnExpression(oldSelect.Alias, new NLinq.Expressions.MemberExpression(((NLinq.Expressions.MemberExpression)entity.Expression).Statement, entity.Expression)); } else throw new NotSupportedException(); if (column != null) columns.Add(column); } if (oldSelect.OrderBy != null && oldSelect.OrderBy.Count > 0) { List<Evaluant.NLinq.Expressions.OrderByCriteria> criterias = new List<NLinq.Expressions.OrderByCriteria>(); foreach (var criteria in oldSelect.OrderBy.Criterias) { if (criteria.Expression != null) { if (criteria.Expression.ExpressionType == NLinq.Expressions.ExpressionTypes.MemberAccess) { criterias.Add(new NLinq.Expressions.OrderByCriteria(new ColumnExpression(oldSelect.Alias, (NLinq.Expressions.Identifier)((NLinq.Expressions.MemberExpression)criteria.Expression).Statement), criteria.Ascending)); } } } if (criterias.Count > 0) select.OrderBy = new NLinq.Expressions.OrderByClause(criterias); } //Since we include a surrounding select, we need to clone some information with alias changing var aliasChanger = new LazyAliasResolver(new Dictionary<TableAlias, TableAlias> { { TableAlias.All, oldSelect.Alias } }); select.Columns = aliasChanger.VisitColumns(columns); select.OrderBy = aliasChanger.VisitOrderBy(select.OrderBy); oldSelect.OrderBy = null; return select; } if (item.Identifier.Text == "First") { Visit(expression.Previous); select.Top = 1; return select; } if (item.Identifier.Text == "Last") { Visit(expression.Previous); if (select.OrderBy != null && select.OrderBy.Criterias != null && select.OrderBy.Criterias.Count > 0) { foreach (NLinq.Expressions.OrderByCriteria criteria in select.OrderBy.Criterias) { criteria.Ascending = !criteria.Ascending; } } else throw new NotSupportedException("To use Last or LastOrDefault, you have to specify an order in your query."); select.Top = 1; return select; } if (item.Identifier.Text == "Any") { if (expression.Previous.ExpressionType != NLinq.Expressions.ExpressionTypes.Quote) { select = new SelectStatement(new TableAlias()); select.Columns = new[] { new ComplexColumnExpression( null, new Constant(1, System.Data.DbType.Int32)) }; select.Where = new NLinq.Expressions.WhereClause(Visit(expression.Previous)); var result = new Exists(select); select = oldSelect; return result; } return new Exists(Visit(expression.Previous)); } if (item.Identifier.Text == "Distinct") { Visit(expression.Previous); select.Distinct = true; return select; } return expression; select = new SelectStatement(new TableAlias()); Visit(expression.Previous); SelectStatement previousSelect = select; select = oldSelect; if (item.Parameters.Length == 0) return new SelectStatement(new TableAlias(), new IAliasedExpression[] { new Aggregate(item.Identifier, ColumnExpression.AllColumns) }, new FromClause(previousSelect), null, null); else return new SelectStatement(new TableAlias(), new IAliasedExpression[] { new Aggregate(item.Identifier, item.Parameters) }, new FromClause(previousSelect), null, null); } else { IAliasedExpression result; if (expression.Previous is Evaluant.NLinq.Expressions.MemberExpression) { //If we are aggregating results if (select == null) { Visit(expression.Previous); SelectStatement oldSelect = select; select = new SelectStatement(new TableAlias()); var columns = new IAliasedExpression[] { new Aggregate(aggregateType, new Constant(1, System.Data.DbType.Int32)) }; select.Columns = columns; select.From = new FromClause(oldSelect); //Prevent order by if counting (useless, and causes crashes on SQLServer if (oldSelect.OrderBy != null) oldSelect.OrderBy = null; return select; } else { SelectStatement oldSelect = select; select = new SelectStatement(new TableAlias()); //from var veryPrevious in oldSelect.From //from var a in expression.Previous //where veryPrevious==oldSelect.Select //select a getAlias = true; EntityIdentifier identifier = (EntityIdentifier)Visit(expression); getAlias = false; getPreviousType = true; EntityExpression previousEntity = (EntityExpression)Visit(expression.Previous); getPreviousType = false; select.From = oldSelect.From; Evaluant.NLinq.Expressions.Identifier generatedIdentifier = new Evaluant.NLinq.Expressions.Identifier("source" + expression.GetHashCode()); generatedIdentifier = new EntityIdentifier(generatedIdentifier, new EntityExpression(identifier.Entity.Alias) { Type = previousEntity.Type, Expression = generatedIdentifier }); Evaluant.NLinq.Expressions.Identifier generatedTargetIdentifier = new Evaluant.NLinq.Expressions.Identifier("target" + expression.GetHashCode()); generatedTargetIdentifier = new EntityIdentifier(generatedTargetIdentifier, new EntityExpression(new TableAlias()) { Type = previousEntity.Type, Expression = generatedTargetIdentifier }); //from generatedIdentifier //from generatedTargetIdentifier in expression //where generatedIdentifier==identifier //select generatedTargetIdentifier //Add a join to load the reference on which we want to aggregate Evaluant.NLinq.Expressions.QueryExpression query = new Evaluant.NLinq.Expressions.QueryExpression( new NLinq.Expressions.FromClause(identifier.Entity.Type, generatedIdentifier, null), new Evaluant.NLinq.Expressions.QueryBody( new Evaluant.NLinq.Expressions.ClauseList{ new NLinq.Expressions.FromClause(previousEntity.Type, generatedTargetIdentifier, expression.Previous), new Evaluant.NLinq.Expressions.WhereClause( new Evaluant.NLinq.Expressions.BinaryExpression( Evaluant.NLinq.Expressions.BinaryExpressionType.Equal, new EntityReferenceExpression(((EntityIdentifier)generatedIdentifier).Entity), new EntityReferenceExpression(identifier.Entity))) }, new Evaluant.NLinq.Expressions.SelectClause( new EntityReferenceExpression(((EntityIdentifier)generatedTargetIdentifier).Entity)), null)); result = (IAliasedExpression)Visit(query); select = oldSelect; } } else result = (IAliasedExpression)Visit(expression.Previous); if (item.Parameters.Length == 0) result = new SelectStatement(new TableAlias(), new IAliasedExpression[] { new Aggregate(aggregateType, ColumnExpression.AllColumns) }, new FromClause(result), null, null); else result = new SelectStatement(new TableAlias(), new IAliasedExpression[] { new Aggregate(aggregateType, item.Parameters) }, new FromClause(result), null, null); return (NLinq.Expressions.Expression)result; } } return base.Visit(expression); //throw new NotSupportedException("There should be at least one previous"); }