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));
        }
예제 #2
0
        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));
        }