private Expression BuildIndexExpression(SqlTableExpression table, string indexName, Tuple <IndexAttribute, PropertyDescriptor>[] properties) { Expression where = null; var unique = properties.Select(c => c.Item1).Any(c => c.Unique); var lowercaseIndex = properties.Any(c => c.Item1.LowercaseIndex); var indexType = properties.Select(c => c.Item1.IndexType).FirstOrDefault(c => c != IndexType.Default); var sorted = properties.OrderBy(c => c.Item1.CompositeOrder, Comparer <int> .Default); var indexedColumns = new List <SqlIndexedColumnExpression>(); foreach (var attributeAndProperty in sorted.Where(c => !c.Item1.IncludeOnly)) { foreach (var columnInfo in QueryBinder.GetColumnInfos(this.model.TypeDescriptorProvider, attributeAndProperty.Item2)) { indexedColumns.Add(new SqlIndexedColumnExpression(new SqlColumnExpression(columnInfo.DefinitionProperty.PropertyType, null, columnInfo.ColumnName), attributeAndProperty.Item1.SortOrder, attributeAndProperty.Item1.LowercaseIndex)); } } var includedColumns = new List <SqlIndexedColumnExpression>(); foreach (var attributeAndProperty in sorted.Where(c => c.Item1.IncludeOnly)) { foreach (var columnInfo in QueryBinder.GetColumnInfos(this.model.TypeDescriptorProvider, attributeAndProperty.Item2)) { includedColumns.Add(new SqlIndexedColumnExpression(new SqlColumnExpression(columnInfo.DefinitionProperty.PropertyType, null, columnInfo.ColumnName))); } } Debug.Assert(properties.Select(c => c.Item2.PropertyInfo.DeclaringType).Distinct().Count() == 1); var parameterExpression = Expression.Parameter(properties.First().Item2.PropertyInfo.DeclaringType); foreach (var attributeAndProperty in sorted.Where(c => !c.Item1.Condition.IsNullOrEmpty())) { var expression = ComputedExpressionParser.Parse(attributeAndProperty.Item1.Condition, attributeAndProperty.Item2, parameterExpression, null, typeof(bool)); if (expression == null) { continue; } where = where == null ? expression.Body : Expression.And(where, expression.Body); } if (where != null) { where = Expression.Lambda(where, parameterExpression); var call = Expression.Call(null, MethodInfoFastRef.QueryableWhereMethod.MakeGenericMethod(parameterExpression.Type), Expression.Constant(null, typeof(DataAccessObjects <>).MakeGenericType(parameterExpression.Type)), where); var projection = (SqlProjectionExpression)SqlQueryProvider.Optimize(this.dataAccessModel, SqlQueryProvider.Bind(this.dataAccessModel, this.sqlDataTypeProvider, call)); where = projection.Select.Where; where = AliasReferenceReplacer.Replace(where, ((SqlTableExpression)projection.Select.From).Alias, null); } return(new SqlCreateIndexExpression(indexName, table, unique, lowercaseIndex, indexType, false, indexedColumns, includedColumns, where)); }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { if (selectExpression.Skip != null) { var rowNumber = new SqlFunctionCallExpression(typeof(int), "ROW_NUMBER"); var oldAliases = (selectExpression.From as ISqlExposesAliases)?.Aliases; var innerSelectWithRowAlias = selectExpression.Alias + "_ROW"; var cols = selectExpression.Columns.Select(c => new SqlColumnDeclaration(c.Name, new SqlColumnExpression(c.Expression.Type, selectExpression.Alias, c.Name))).ToList(); var over = new SqlOverExpression(rowNumber, selectExpression.OrderBy?.Cast <SqlOrderByExpression>().ToReadOnlyCollection() ?? cols.Select(c => new SqlOrderByExpression(OrderType.Ascending, c.Expression)).ToReadOnlyCollection()); if (oldAliases != null) { over = (SqlOverExpression)AliasReferenceReplacer.Replace(over, oldAliases.Contains, selectExpression.Alias); } var rowColumn = new SqlColumnDeclaration(RowColumnName, over); cols.Add(rowColumn); var innerSelectWithRowColumns = cols.ToReadOnlyCollection(); var innerSelectWithRow = new SqlSelectExpression(selectExpression.Type, innerSelectWithRowAlias, innerSelectWithRowColumns, selectExpression.ChangeOrderBy(null).ChangeSkipTake(null, null), null, null, null, false, null, null, false); var outerColumns = selectExpression.Columns.Select(c => new SqlColumnDeclaration(c.Name, new SqlColumnExpression(c.Expression.Type, innerSelectWithRowAlias, c.Name))); Expression rowPredicate = Expression.GreaterThan(new SqlColumnExpression(typeof(int), innerSelectWithRowAlias, rowColumn.Name), selectExpression.Skip); if (selectExpression.Take != null && !(selectExpression.Take is SqlTakeAllValueExpression)) { rowPredicate = Expression.And ( rowPredicate, Expression.LessThanOrEqual(new SqlColumnExpression(typeof(int), innerSelectWithRowAlias, rowColumn.Name), Expression.Add(selectExpression.Skip, selectExpression.Take)) ); } var newOrderBy = selectExpression .OrderBy? .Select(c => oldAliases == null ? c : AliasReferenceReplacer.Replace(c, oldAliases.Contains, innerSelectWithRowAlias)) .Concat(new SqlOrderByExpression(OrderType.Ascending, new SqlColumnExpression(typeof(int), innerSelectWithRowAlias, rowColumn.Name))) .ToReadOnlyCollection(); var retval = new SqlSelectExpression(selectExpression.Type, selectExpression.Alias, outerColumns, innerSelectWithRow, rowPredicate, newOrderBy, selectExpression.ForUpdate); return(retval); } return(base.VisitSelect(selectExpression)); }