コード例 #1
0
        internal static Expression Bind(DataAccessModel dataAccessModel, SqlDataTypeProvider sqlDataTypeProvider, Expression expression)
        {
            var placeholderCount = -1;

            expression = Evaluator.PartialEval(expression, ref placeholderCount);
            expression = QueryBinder.Bind(dataAccessModel, expression);
            expression = SqlEnumTypeNormalizer.Normalize(expression, sqlDataTypeProvider.GetTypeForEnums());
            expression = Evaluator.PartialEval(expression, ref placeholderCount);
            expression = SqlNullComparisonCoalescer.Coalesce(expression);
            expression = SqlTupleOrAnonymousTypeComparisonExpander.Expand(expression);
            expression = SqlObjectOperandComparisonExpander.Expand(expression);
            expression = SqlRedundantFunctionCallRemover.Remove(expression);

            return(expression);
        }
コード例 #2
0
ファイル: SqlQueryProvider.cs プロジェクト: ciker/Shaolinq
        public static Expression Optimize(Expression expression, Type typeForEnums, bool simplerPartialVal = true)
        {
            expression = SqlObjectOperandComparisonExpander.Expand(expression);
            expression = SqlEnumTypeNormalizer.Normalize(expression, typeForEnums);
            expression = SqlGroupByCollator.Collate(expression);
            expression = SqlAggregateSubqueryRewriter.Rewrite(expression);
            expression = SqlUnusedColumnRemover.Remove(expression);
            expression = SqlRedundantColumnRemover.Remove(expression);
            expression = SqlRedundantSubqueryRemover.Remove(expression);
            expression = SqlFunctionCoalescer.Coalesce(expression);
            expression = SqlExistsSubqueryOptimizer.Optimize(expression);
            expression = SqlRedundantBinaryExpressionsRemover.Remove(expression);
            expression = SqlCrossJoinRewriter.Rewrite(expression);

            if (simplerPartialVal)
            {
                expression = Evaluator.PartialEval(expression, c => c.NodeType != (ExpressionType)SqlExpressionType.ConstantPlaceholder && Evaluator.CanBeEvaluatedLocally(c));
            }
            else
            {
                expression = Evaluator.PartialEval(expression);
            }

            expression = SqlRedundantFunctionCallRemover.Remove(expression);
            expression = SqlConditionalEliminator.Eliminate(expression);
            expression = SqlExpressionCollectionOperationsExpander.Expand(expression);
            expression = SqlSumAggregatesDefaultValueCoalescer.Coalesce(expression);
            expression = SqlOrderByRewriter.Rewrite(expression);

            var rewritten = SqlCrossApplyRewriter.Rewrite(expression);

            if (rewritten != expression)
            {
                expression = rewritten;

                expression = SqlUnusedColumnRemover.Remove(expression);
                expression = SqlRedundantColumnRemover.Remove(expression);
                expression = SqlRedundantSubqueryRemover.Remove(expression);
                expression = SqlOrderByRewriter.Rewrite(expression);
            }

            return(expression);
        }
コード例 #3
0
        public static void DeleteWhere <T>(this DataAccessObjectsQueryable <T> queryable, Expression <Func <T, bool> > condition)
            where T : DataAccessObject
        {
            queryable.DataAccessModel.Flush();

            var transactionContext = queryable.DataAccessModel.AmbientTransactionManager.GetCurrentContext(true);

            using (var acquisition = transactionContext.AcquirePersistenceTransactionContext(queryable.DataAccessModel.GetCurrentSqlDatabaseContext()))
            {
                var expression = (Expression)Expression.Call(null, MethodCache <T> .DeleteMethod, Expression.Constant(queryable, typeof(DataAccessObjectsQueryable <T>)), condition);

                expression = Evaluator.PartialEval(expression);
                expression = QueryBinder.Bind(queryable.DataAccessModel, expression, queryable.ElementType, queryable.ExtraCondition);
                expression = SqlObjectOperandComparisonExpander.Expand(expression);
                expression = SqlQueryProvider.Optimize(expression, transactionContext.SqlDatabaseContext.SqlDataTypeProvider.GetTypeForEnums());

                acquisition.SqlDatabaseCommandsContext.Delete((SqlDeleteExpression)expression);
            }
        }
コード例 #4
0
        public override void Delete(Type type, IEnumerable <DataAccessObject> dataAccessObjects)
        {
            var typeDescriptor = this.DataAccessModel.GetTypeDescriptor(type);
            var parameter      = Expression.Parameter(typeDescriptor.Type, "value");

            Expression body = null;

            foreach (var dataAccessObject in dataAccessObjects)
            {
                var currentExpression = Expression.Equal(parameter, Expression.Constant(dataAccessObject));

                if (body == null)
                {
                    body = currentExpression;
                }
                else
                {
                    body = Expression.OrElse(body, currentExpression);
                }
            }

            if (body == null)
            {
                return;
            }

            var condition  = Expression.Lambda(body, parameter);
            var expression = (Expression)Expression.Call(null, GetDeleteMethod(typeDescriptor.Type), Expression.Constant(null, typeDescriptor.Type), condition);

            expression = Evaluator.PartialEval(expression);
            expression = QueryBinder.Bind(this.DataAccessModel, expression, null, null);
            expression = SqlObjectOperandComparisonExpander.Expand(expression);
            expression = SqlQueryProvider.Optimize(expression, this.SqlDatabaseContext.SqlDataTypeProvider.GetTypeForEnums());

            this.Delete((SqlDeleteExpression)expression);
        }
コード例 #5
0
        protected virtual IDbCommand BuildUpdateCommand(TypeDescriptor typeDescriptor, DataAccessObject dataAccessObject)
        {
            bool       valuesPredicated;
            bool       primaryKeysPredicated;
            IDbCommand command = null;
            SqlCachedUpdateInsertFormatValue cachedValue;
            var requiresIdentityInsert = dataAccessObject.ToObjectInternal().HasAnyChangedPrimaryKeyServerSideProperties;
            var updatedProperties      = dataAccessObject.ToObjectInternal().GetChangedPropertiesFlattened(out valuesPredicated);

            if (updatedProperties.Count == 0)
            {
                return(null);
            }

            var success     = false;
            var primaryKeys = dataAccessObject.ToObjectInternal().GetPrimaryKeysForUpdateFlattened(out primaryKeysPredicated);

            if (valuesPredicated || primaryKeysPredicated)
            {
                return(BuildUpdateCommandForDeflatedPredicated(typeDescriptor, dataAccessObject, valuesPredicated, primaryKeysPredicated, updatedProperties, primaryKeys));
            }

            var commandKey = new SqlCachedUpdateInsertFormatKey(dataAccessObject.GetType(), updatedProperties, requiresIdentityInsert);

            if (this.TryGetUpdateCommand(commandKey, out cachedValue))
            {
                try
                {
                    command             = this.CreateCommand();
                    command.CommandText = cachedValue.formatResult.CommandText;

                    this.FillParameters(command, cachedValue, updatedProperties, primaryKeys);

                    success = true;

                    return(command);
                }
                finally
                {
                    if (!success)
                    {
                        command?.Dispose();
                    }
                }
            }

            var constantPlaceholdersCount = 0;
            var valueIndexesToParameterPlaceholderIndexes      = new int[updatedProperties.Count];
            var primaryKeyIndexesToParameterPlaceholderIndexes = new int[primaryKeys.Length];

            var assignments = new List <Expression>(updatedProperties.Count);

            foreach (var updated in updatedProperties)
            {
                var value = (Expression) new SqlConstantPlaceholderExpression(constantPlaceholdersCount++, Expression.Constant(updated.Value, updated.PropertyType.CanBeNull() ? updated.PropertyType : updated.PropertyType.MakeNullable()));

                if (value.Type != updated.PropertyType)
                {
                    value = Expression.Convert(value, updated.PropertyType);
                }

                assignments.Add(new SqlAssignExpression(new SqlColumnExpression(updated.PropertyType, null, updated.PersistedName), value));
            }

            Expression where = null;

            Debug.Assert(primaryKeys.Length > 0);

            foreach (var primaryKey in primaryKeys)
            {
                var value       = primaryKey.Value;
                var placeholder = (Expression) new SqlConstantPlaceholderExpression(constantPlaceholdersCount++, Expression.Constant(value, primaryKey.PropertyType.CanBeNull() ? primaryKey.PropertyType : primaryKey.PropertyType.MakeNullable()));

                if (placeholder.Type != primaryKey.PropertyType)
                {
                    placeholder = Expression.Convert(placeholder, primaryKey.PropertyType);
                }

                var currentExpression = Expression.Equal(new SqlColumnExpression(primaryKey.PropertyType, null, primaryKey.PersistedName), placeholder);

                where = where == null ? currentExpression : Expression.And(where, currentExpression);
            }

            for (var i = 0; i < assignments.Count; i++)
            {
                valueIndexesToParameterPlaceholderIndexes[i] = i;
            }

            for (var i = 0; i < primaryKeys.Length; i++)
            {
                primaryKeyIndexesToParameterPlaceholderIndexes[i] = i + assignments.Count;
            }

            var expression = (Expression) new SqlUpdateExpression(new SqlTableExpression(typeDescriptor.PersistedName), assignments, where, requiresIdentityInsert);

            expression = SqlObjectOperandComparisonExpander.Expand(expression);

            var result = this.SqlDatabaseContext.SqlQueryFormatterManager.Format(expression, SqlQueryFormatterOptions.Default);

            try
            {
                command             = this.CreateCommand();
                command.CommandText = result.CommandText;

                cachedValue = new SqlCachedUpdateInsertFormatValue {
                    formatResult = result, valueIndexesToParameterPlaceholderIndexes = valueIndexesToParameterPlaceholderIndexes, primaryKeyIndexesToParameterPlaceholderIndexes = primaryKeyIndexesToParameterPlaceholderIndexes
                };

                if (result.Cacheable)
                {
                    this.CacheUpdateCommand(commandKey, cachedValue);
                }

                FillParameters(command, cachedValue, null, null);

                success = true;

                return(command);
            }
            finally
            {
                if (!success)
                {
                    command?.Dispose();
                }
            }
        }
コード例 #6
0
        protected override Expression VisitMemberInit(MemberInitExpression expression)
        {
            var previousCurrentNewExpressionType = this.currentNewExpressionType;

            this.currentNewExpressionType = expression.NewExpression.Type;

            Expression nullCheck = null;

            foreach (var value in SqlObjectOperandComparisonExpander.GetPrimaryKeyElementalExpressions(expression))
            {
                Expression current;

                if (value.NodeType == (ExpressionType)SqlExpressionType.Column)
                {
                    current = this.ConvertColumnToIsNull((SqlColumnExpression)value);
                }
                else
                {
                    var visited = this.Visit(value);

                    if (visited.Type.IsClass || visited.Type.IsNullableType())
                    {
                        current = Expression.Equal(Expression.Convert(visited, visited.Type), Expression.Constant(null, visited.Type));
                    }
                    else
                    {
                        current = Expression.Equal(Expression.Convert(visited, visited.Type.MakeNullable()), Expression.Constant(null, visited.Type.MakeNullable()));
                    }
                }

                if (nullCheck == null)
                {
                    nullCheck = current;
                }
                else
                {
                    nullCheck = Expression.Or(nullCheck, current);
                }
            }

            var retval = base.VisitMemberInit(expression);

            this.currentNewExpressionType = previousCurrentNewExpressionType;

            if (typeof(DataAccessObject).IsAssignableFrom(retval.Type))
            {
                var submitToCacheMethod        = typeof(IDataAccessObjectInternal).GetMethod("SubmitToCache", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
                var resetModifiedMethod        = typeof(IDataAccessObjectInternal).GetMethod("ResetModified", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
                var finishedInitializingMethod = typeof(IDataAccessObjectInternal).GetMethod("FinishedInitializing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);

                retval = Expression.Convert(Expression.Call(Expression.Call(Expression.Call(Expression.Convert(retval, typeof(IDataAccessObjectInternal)), finishedInitializingMethod), resetModifiedMethod), submitToCacheMethod), retval.Type);
            }

            if (nullCheck != null)
            {
                return(Expression.Condition(nullCheck, Expression.Constant(null, retval.Type), retval));
            }
            else
            {
                return(retval);
            }
        }
コード例 #7
0
        protected override Expression VisitMemberInit(MemberInitExpression expression)
        {
            Expression nullCheck      = null;
            var        savedRootLevel = this.atRootLevel;

            try
            {
                if (this.atRootLevel)
                {
                    this.atRootLevel = false;

                    if (typeof(DataAccessObject).IsAssignableFrom(expression.NewExpression.Type))
                    {
                        foreach (var value in SqlObjectOperandComparisonExpander.GetPrimaryKeyElementalExpressions(expression))
                        {
                            this.treatColumnsAsNullable = true;
                            var visited = Visit(value);
                            this.treatColumnsAsNullable = false;

                            this.scope.rootPrimaryKeys.Add(visited.Type.IsValueType ? Expression.Convert(visited, typeof(object)) : visited);
                        }
                    }
                }

                var previousCurrentNewExpressionTypeDescriptor = this.currentNewExpressionTypeDescriptor;

                this.currentNewExpressionTypeDescriptor = this.dataAccessModel.TypeDescriptorProvider.GetTypeDescriptor(expression.NewExpression.Type);

                if (typeof(DataAccessObject).IsAssignableFrom(expression.NewExpression.Type))
                {
                    foreach (var value in SqlObjectOperandComparisonExpander.GetPrimaryKeyElementalExpressions(expression))
                    {
                        Expression current;

                        if (value.NodeType == (ExpressionType)SqlExpressionType.Column)
                        {
                            current = ConvertColumnToIsNull((SqlColumnExpression)value);
                        }
                        else
                        {
                            var visited = Visit(value);

                            if (visited.Type.IsClass || visited.Type.IsNullableType())
                            {
                                current = Expression.Equal(Expression.Convert(visited, visited.Type), Expression.Constant(null, visited.Type));
                            }
                            else
                            {
                                current = Expression.Equal(Expression.Convert(visited, visited.Type.MakeNullable()), Expression.Constant(null, visited.Type.MakeNullable()));
                            }
                        }

                        if (nullCheck == null)
                        {
                            nullCheck = current;
                        }
                        else
                        {
                            nullCheck = Expression.Or(nullCheck, current);
                        }
                    }
                }

                var retval = base.VisitMemberInit(expression);

                this.currentNewExpressionTypeDescriptor = previousCurrentNewExpressionTypeDescriptor;

                if (typeof(DataAccessObject).IsAssignableFrom(retval.Type))
                {
                    var methodCalls = Expression.Call(Expression.Call(Expression.Call(Expression.Call(Expression.Convert(retval, typeof(IDataAccessObjectInternal)), this.finishedInitializingMethod), this.resetModifiedMethod), this.submitToCacheMethod), this.notifyReadMethod);

                    retval = Expression.Convert(methodCalls, retval.Type);
                }

                if (nullCheck != null)
                {
                    return(Expression.Condition(nullCheck, Expression.Constant(null, retval.Type), retval));
                }
                else
                {
                    return(retval);
                }
            }
            finally
            {
                this.atRootLevel = savedRootLevel;
            }
        }
コード例 #8
0
        protected virtual IDbCommand BuildUpdateCommand(TypeDescriptor typeDescriptor, DataAccessObject dataAccessObject)
        {
            IDbCommand      command;
            SqlCommandValue sqlCommandValue;
            var             updatedProperties = dataAccessObject.GetAdvanced().GetChangedPropertiesFlattened();

            if (updatedProperties.Count == 0)
            {
                return(null);
            }

            var primaryKeys = dataAccessObject.GetAdvanced().GetPrimaryKeysForUpdateFlattened();
            var commandKey  = new SqlCommandKey(dataAccessObject.GetType(), updatedProperties);

            if (this.TryGetUpdateCommand(commandKey, out sqlCommandValue))
            {
                command             = this.CreateCommand();
                command.CommandText = sqlCommandValue.commandText;
                this.FillParameters(command, updatedProperties, primaryKeys);

                return(command);
            }

            var assignments = updatedProperties.Select(c => (Expression) new SqlAssignExpression(new SqlColumnExpression(c.PropertyType, null, c.PersistedName), Expression.Constant(c.Value))).ToReadOnlyList();

            Expression where = null;

            var i = 0;

            Debug.Assert(primaryKeys.Length > 0);

            foreach (var primaryKey in primaryKeys)
            {
                var currentExpression = Expression.Equal(new SqlColumnExpression(primaryKey.PropertyType, null, primaryKey.PersistedName), Expression.Constant(primaryKey.Value));

                if (where == null)
                {
                    where = currentExpression;
                }
                else
                {
                    where = Expression.And(where, currentExpression);
                }

                i++;
            }

            var expression = new SqlUpdateExpression(new SqlTableExpression(typeDescriptor.PersistedName), assignments, where);

            expression = (SqlUpdateExpression)SqlObjectOperandComparisonExpander.Expand(expression);

            var result = this.SqlDatabaseContext.SqlQueryFormatterManager.Format(expression, SqlQueryFormatterOptions.Default & ~SqlQueryFormatterOptions.OptimiseOutConstantNulls);

            command = this.CreateCommand();

            command.CommandText = result.CommandText;
            this.CacheUpdateCommand(commandKey, new SqlCommandValue()
            {
                commandText = command.CommandText
            });
            this.FillParameters(command, updatedProperties, primaryKeys);

            return(command);
        }