private void UnaryExpression(UnaryExpression body, SqlBuilderState state) { // simple case of a ! prior to a function call if (body.NodeType == ExpressionType.Not && body.Operand is MethodCallExpression) { MethodCallExpression(body.Operand as MethodCallExpression, state, true); return; } // simple case of a ! prior to a property call if (body.NodeType == ExpressionType.Not && body.Operand is MemberExpression) { MemberExpression(body.Operand as MemberExpression, state, true); return; } // simple case of a ! prior to a binary expression if (body.NodeType == ExpressionType.Not && body.Operand is BinaryExpression) { BinaryExpression(body.Operand as BinaryExpression, state, true); return; } throw new NotSupportedException(); }
public void Interpret(MethodCallExpression expression, SqlBuilderState state) { var orderByExpression = expression.Arguments[1]; if (orderByExpression is UnaryExpression) { var unaryOrderByExpression = orderByExpression as UnaryExpression; var operandExpression = unaryOrderByExpression.Operand as Expression; if (operandExpression is LambdaExpression) { var lamdaOperandExpression = operandExpression as LambdaExpression; var bodyExpression = lamdaOperandExpression.Body; if (bodyExpression is MemberExpression) { var memberBodyExpression = bodyExpression as MemberExpression; var mi = memberBodyExpression.Member; var fieldName = GetFieldName(mi); state.OrderBy.Add(string.Format("t.[{0}]{1}", fieldName, Ascending ? string.Empty : " DESC")); } else { throw new NotImplementedException("Unable to resolve value for OrderBy"); } } else { throw new NotImplementedException("Unable to resolve value for OrderBy"); } } else { throw new NotImplementedException("Unable to resolve value for OrderBy"); } }
public void Interpret(MethodCallExpression expression, SqlBuilderState state) { var primaryKeyExpression = expression.Arguments[1]; if (primaryKeyExpression is ConstantExpression) { // create a new expression to do the where clause var elementType = expression.Type; var tableInfo = GetTableInfo(elementType); // check that there is a primary key if (tableInfo.PrimaryKeyFieldNames.Count == 0) { throw new NotSupportedException(string.Format("Type {0} does not have any members with the [Key] attribute applied", elementType.Name)); } // can only deal with single element primary keys at the moment if (tableInfo.PrimaryKeyFieldNames.Count > 1) { throw new NotImplementedException(string.Format("Type {0} has more than one member with the [Key] attribute applied", elementType.Name)); } // add the parameter and where clause string parameterName = state.GetNextParameter(); state.Parameters.Add(parameterName, (primaryKeyExpression as ConstantExpression).Value); state.Where.AppendFormat("( [{0}] = @{1} )", tableInfo.PrimaryKeyFieldNames[0], parameterName); } else { throw new NotSupportedException("Unable to resolve value for RowAt()"); } }
public void Interpret( MethodCallExpression expression, SqlBuilderState state ) { var orderByExpression = expression.Arguments[ 1 ]; if ( orderByExpression is UnaryExpression ) { var unaryOrderByExpression = orderByExpression as UnaryExpression; var operandExpression = unaryOrderByExpression.Operand as Expression; if ( operandExpression is LambdaExpression ) { var lamdaOperandExpression = operandExpression as LambdaExpression; var bodyExpression = lamdaOperandExpression.Body; if ( bodyExpression is MemberExpression ) { var memberBodyExpression = bodyExpression as MemberExpression; var mi = memberBodyExpression.Member; var fieldName = GetFieldName( mi ); state.OrderBy.Add( string.Format( "t.[{0}]{1}", fieldName, Ascending ? string.Empty : " DESC" ) ); } else throw new NotImplementedException( "Unable to resolve value for OrderBy" ); } else throw new NotImplementedException( "Unable to resolve value for OrderBy" ); } else throw new NotImplementedException( "Unable to resolve value for OrderBy" ); }
private void ProcessExpression(Expression expression, SqlBuilderState state) { if (expression is LambdaExpression) { var lambdaOperandExpression = expression as LambdaExpression; ProcessExpression(lambdaOperandExpression.Body, state); } else if (expression is UnaryExpression) { UnaryExpression(expression as UnaryExpression, state); } else if (expression is BinaryExpression) { BinaryExpression(expression as BinaryExpression, state); } else if (expression is MemberExpression) { MemberExpression(expression as MemberExpression, state); } else if (expression is MethodCallExpression) { MethodCallExpression(expression as MethodCallExpression, state); } else { throw new NotSupportedException(); } }
public void Interpret( MethodCallExpression expression, SqlBuilderState state ) { var primaryKeyExpression = expression.Arguments[ 1 ]; if ( primaryKeyExpression is ConstantExpression ) { // create a new expression to do the where clause var elementType = expression.Type; var tableInfo = GetTableInfo( elementType ); // check that there is a primary key if ( tableInfo.PrimaryKeyFieldNames.Count == 0 ) throw new NotSupportedException( string.Format( "Type {0} does not have any members with the [Key] attribute applied", elementType.Name ) ); // can only deal with single element primary keys at the moment if ( tableInfo.PrimaryKeyFieldNames.Count > 1 ) throw new NotImplementedException( string.Format( "Type {0} has more than one member with the [Key] attribute applied", elementType.Name ) ); // add the parameter and where clause string parameterName = state.GetNextParameter(); state.Parameters.Add( parameterName, ( primaryKeyExpression as ConstantExpression ).Value ); state.Where.AppendFormat( "( [{0}] = @{1} )", tableInfo.PrimaryKeyFieldNames[0], parameterName ); } else throw new NotSupportedException( "Unable to resolve value for RowAt()" ); }
private static string BuildSqlStatement(SqlBuilderState state) { // get the database table name from the type or the table attribute TableInfo table = GetTableInfo(state.ElementType); // if there were no specific fields then add the field names from the type if (state.FieldNames.Count == 0) { state.FieldNames.AddRange(table.FieldNames); } // build up the SQL var sb = new StringBuilder("SELECT "); // append the top + fields if (state.Top.HasValue) { state.Parameters.Add("top", state.Top.Value, DbType.Int32); sb.Append("TOP (@top) "); } // distinct if (state.Distinct) { sb.Append("DISTINCT "); } // field list sb.Append(string.Join(", ", state.FieldNames.Select(m => "t.[" + m + "]"))); // append the from sb.AppendFormat(" FROM [{0}].[{1}] AS t ", table.SchemaName, table.TableName); // append the hints if (state.Hints.Count > 0) { sb.Append("WITH ("); sb.Append(string.Join(", ", state.Hints)); sb.Append(")"); } // append the where clause if (state.Where.Length != 0) { sb.Append("WHERE "); sb.Append(state.Where.ToString()); } // append the order by if (state.OrderBy.Count > 0) { state.OrderBy.Reverse(); sb.Append("ORDER BY "); sb.Append(string.Join(", ", state.OrderBy)); } return(sb.ToString()); }
public override void Interpret( MethodCallExpression expression, SqlBuilderState state ) { state.Top = 1; // to ensure that just the first row is returned var whereExpression = expression.Arguments[ 1 ]; if ( whereExpression is UnaryExpression ) { base.Interpret( expression, state ); } else throw new NotSupportedException( "Unable to resolve value for First()" ); }
public override void Interpret( MethodCallExpression expression, SqlBuilderState state ) { state.Top = 2; // to ensure that more than one row is return if the expression isn't actually returning a single var whereExpression = expression.Arguments[ 1 ]; if ( whereExpression is UnaryExpression ) { base.Interpret( expression, state ); } else throw new NotSupportedException( "Unable to resolve value for Single()" ); }
private void MemberExpression(MemberExpression body, SqlBuilderState state, bool reversed = false) { if (body.Member.Name == Nullable_HasValue.Name) { string fieldName = GetFieldName((body.Expression as MemberExpression).Member); state.Where.AppendFormat(" ( t.[{0}] IS {1}NULL ) ", fieldName, reversed ? string.Empty : "NOT "); } else { throw new NotSupportedException(); } }
private static string BuildSqlStatement( SqlBuilderState state ) { // get the database table name from the type or the table attribute TableInfo table = GetTableInfo( state.ElementType ); // if there were no specific fields then add the field names from the type if ( state.FieldNames.Count == 0 ) state.FieldNames.AddRange( table.FieldNames ); // build up the SQL var sb = new StringBuilder( "SELECT " ); // append the top + fields if ( state.Top.HasValue ) { state.Parameters.Add( "top", state.Top.Value, DbType.Int32 ); sb.Append( "TOP (@top) " ); } // distinct if ( state.Distinct ) sb.Append( "DISTINCT " ); // field list sb.Append( string.Join( ", ", state.FieldNames.Select( m => "t.[" + m + "]" ) ) ); // append the from sb.AppendFormat( " FROM [{0}].[{1}] AS t ", table.SchemaName, table.TableName ); // append the hints if ( state.Hints.Count > 0 ) { sb.Append( "WITH (" ); sb.Append( string.Join( ", ", state.Hints ) ); sb.Append( ")" ); } // append the where clause if ( state.Where.Length != 0 ) { sb.Append( "WHERE " ); sb.Append( state.Where.ToString() ); } // append the order by if ( state.OrderBy.Count > 0 ) { state.OrderBy.Reverse(); sb.Append( "ORDER BY " ); sb.Append( string.Join( ", ", state.OrderBy ) ); } return sb.ToString(); }
public void Interpret( MethodCallExpression expression, SqlBuilderState state ) { var topExpression = expression.Arguments[ 1 ]; if ( topExpression is ConstantExpression ) { var constantTopExpression = topExpression as ConstantExpression; if ( constantTopExpression.Type == typeof( Int32 ) ) state.Top = (int)constantTopExpression.Value; else state.Top = Convert.ToInt32( constantTopExpression.Value ); } else throw new NotSupportedException( "Unable to resolve value for Take()" ); }
private void EvaluateExpression() { if (_evaluated) { return; } var state = new SqlBuilderState(); var expression = _expression; while (expression != null) { if (expression is ConstantExpression) { var constantExpression = expression as ConstantExpression; expression = null; // end of the line // should be an IQueryable<T> where T is the resulting table state.ElementType = constantExpression.Type.GetGenericArguments()[0]; } else if (expression is MethodCallExpression) { var methodCallExpression = expression as MethodCallExpression; if (methodCallExpression.Arguments.Count == 0) { throw new NotSupportedException("Method call expression must have at least one argument"); } // up the stack of expressions expression = methodCallExpression.Arguments[0]; // process each method LinqProcessor.Process(methodCallExpression.Method.Name).Interpret(methodCallExpression, state); } else { throw new NotImplementedException("Expression is not handled"); } } // NICE: put the field list into a concurrent shared dictionary _sql = BuildSqlStatement(state); if (state.HasParameters) { _parameters = state.Parameters; } _evaluated = true; }
public override void Interpret(MethodCallExpression expression, SqlBuilderState state) { state.Top = 1; // to ensure that just the first row is returned var whereExpression = expression.Arguments[1]; if (whereExpression is UnaryExpression) { base.Interpret(expression, state); } else { throw new NotSupportedException("Unable to resolve value for First()"); } }
public override void Interpret(MethodCallExpression expression, SqlBuilderState state) { state.Top = 2; // to ensure that more than one row is return if the expression isn't actually returning a single var whereExpression = expression.Arguments[1]; if (whereExpression is UnaryExpression) { base.Interpret(expression, state); } else { throw new NotSupportedException("Unable to resolve value for Single()"); } }
public virtual void Interpret(MethodCallExpression expression, SqlBuilderState state) { var whereExpression = expression.Arguments[1]; if (whereExpression is UnaryExpression) { var unaryWhereExpression = whereExpression as UnaryExpression; var operandExpression = unaryWhereExpression.Operand; ProcessExpression(operandExpression, state); } else { throw new NotSupportedException("Unable to resolve value for Where()"); } }
public void Interpret(MethodCallExpression expression, SqlBuilderState state) { var topExpression = expression.Arguments[1]; if (topExpression is ConstantExpression) { var constantTopExpression = topExpression as ConstantExpression; if (constantTopExpression.Type == typeof(Int32)) { state.Top = (int)constantTopExpression.Value; } else { state.Top = Convert.ToInt32(constantTopExpression.Value); } } else { throw new NotSupportedException("Unable to resolve value for Take()"); } }
private void EvaluateExpression() { if ( _evaluated ) return; var state = new SqlBuilderState(); var expression = _expression; while ( expression != null ) { if ( expression is ConstantExpression ) { var constantExpression = expression as ConstantExpression; expression = null; // end of the line // should be an IQueryable<T> where T is the resulting table state.ElementType = constantExpression.Type.GetGenericArguments()[ 0 ]; } else if ( expression is MethodCallExpression ) { var methodCallExpression = expression as MethodCallExpression; if ( methodCallExpression.Arguments.Count == 0 ) throw new NotSupportedException( "Method call expression must have at least one argument" ); // up the stack of expressions expression = methodCallExpression.Arguments[ 0 ]; // process each method LinqProcessor.Process( methodCallExpression.Method.Name ).Interpret( methodCallExpression, state ); } else throw new NotImplementedException( "Expression is not handled" ); } // NICE: put the field list into a concurrent shared dictionary _sql = BuildSqlStatement( state ); if ( state.HasParameters ) _parameters = state.Parameters; _evaluated = true; }
public void Interpret(MethodCallExpression expression, SqlBuilderState state) { state.Hints.Add("holdlock"); }
public void Interpret(MethodCallExpression expression, SqlBuilderState state) { state.Distinct = true; }
public void Interpret( MethodCallExpression expression, SqlBuilderState state ) { state.Hints.Add( "holdlock" ); }
public void Interpret(MethodCallExpression expression, SqlBuilderState state) { throw new NotImplementedException(string.Format("DapperLinq does not support the {0}() method", (expression as MethodCallExpression).Method.Name)); }
private void BinaryExpression(BinaryExpression body, SqlBuilderState state, bool inverse = false) { var left = body.Left; var right = body.Right; if (body.NodeType == ExpressionType.AndAlso || body.NodeType == ExpressionType.OrElse) { if (inverse) { state.Where.Append("( NOT "); } state.Where.Append("( "); ProcessExpression(left, state); state.Where.Append(body.NodeType == ExpressionType.AndAlso ? " AND " : " OR "); ProcessExpression(right, state); state.Where.Append(" )"); if (inverse) { state.Where.Append(" )"); } } else { // reverse where applicable bool reversed = false; if (left is ConstantExpression && right is MemberExpression) { reversed = true; var swap = right; right = left; left = swap; } if (right is ConstantExpression && left is MemberExpression) { string fieldName = GetFieldName((left as MemberExpression).Member); object value = (right as ConstantExpression).Value; // caching this would lead to caching one or the other depending on whether the original value was NULL or not! // could optimise out non-nullable values if (value == null) { if (body.NodeType == ExpressionType.Equal || body.NodeType == ExpressionType.NotEqual) { bool equal = body.NodeType == ExpressionType.Equal; if (inverse) { equal = !equal; } state.Where.AppendFormat(" ( t.[{0}] {1} NULL ) ", fieldName, equal ? "IS" : "IS NOT"); return; } else { throw new NotSupportedException(); } } else { Operator op; if (!_comparisonOperators.TryGetValue(body.NodeType, out op)) { throw new NotSupportedException(); } string parameterName = state.GetNextParameter(); if (!reversed) { state.Where.AppendFormat(" ( t.[{0}] {1} @{2} ) ", fieldName, op.Value(inverse), parameterName); } else { state.Where.AppendFormat(" ( @{2} {1} t.[{0}] ) ", fieldName, op.Value(inverse), parameterName); } state.Parameters.Add(parameterName, value); } } else if (left is MemberExpression && right is MemberExpression) { Operator op; if (!_comparisonOperators.TryGetValue(body.NodeType, out op)) { throw new NotSupportedException(); } if (!reversed) { state.Where.AppendFormat(" ( t.[{0}] {1} t.[{2}] ) ", GetFieldName((left as MemberExpression).Member), op.Value(inverse), GetFieldName((right as MemberExpression).Member)); } else { state.Where.AppendFormat(" ( t.[{2}] {1} t.[{0}] ) ", GetFieldName((left as MemberExpression).Member), op.Value(inverse), GetFieldName((right as MemberExpression).Member)); } } else { throw new NotSupportedException(); } } }
public void Interpret( MethodCallExpression expression, SqlBuilderState state ) { state.Distinct = true; }
private void MethodCallExpression(MethodCallExpression body, SqlBuilderState state, bool inverse = false) { string negative = inverse ? "NOT " : string.Empty; if (body.Method == String_IsNullOrEmpty) { string fieldName = GetFieldName((body.Arguments[0] as MemberExpression).Member); state.Where.AppendFormat(" ( t.[{0}] IS {1}NULL ) ", fieldName, negative); } else if (body.Method == String_EndsWith || body.Method == String_EndsWithAndComparison) { string fieldName = GetFieldName((body.Object as MemberExpression).Member); Expression valueExpression = body.Arguments[0]; // if comparison is provide ensure it's one that SQL server will respect if (body.Arguments.Count == 2) { CheckArgumentIsValue <StringComparison>(body.Arguments[1], StringComparison.OrdinalIgnoreCase, "EndsWith can only be used with StringComparison.OrdinalIgnoreCase"); } if (valueExpression is ConstantExpression) { var constantValueExpression = valueExpression as ConstantExpression; var parameter = state.GetNextParameter(); if (constantValueExpression.Type == typeof(string) && constantValueExpression.Value != null) { string value = (string)constantValueExpression.Value; state.Parameters.Add(parameter, "%" + value); state.Where.AppendFormat(" ( t.[{0}] {1}LIKE @{2} )", fieldName, negative, parameter); } else { throw new NotSupportedException(); } } else { throw new NotSupportedException(); } } else if (body.Method == String_StartsWith || body.Method == String_StartsWithAndComparison) { string fieldName = GetFieldName((body.Object as MemberExpression).Member); Expression valueExpression = body.Arguments[0]; // if comparison is provide ensure it's one that SQL server will respect if (body.Arguments.Count == 2) { CheckArgumentIsValue <StringComparison>(body.Arguments[1], StringComparison.OrdinalIgnoreCase, "StartsWith can only be used with StringComparison.OrdinalIgnoreCase"); } if (valueExpression is ConstantExpression) { var constantValueExpression = valueExpression as ConstantExpression; var parameter = state.GetNextParameter(); if (constantValueExpression.Type == typeof(string) && constantValueExpression.Value != null) { string value = (string)constantValueExpression.Value; state.Parameters.Add(parameter, value + "%"); state.Where.AppendFormat(" ( t.[{0}] {1}LIKE @{2} )", fieldName, negative, parameter); } else { throw new NotSupportedException(); } } else { throw new NotSupportedException(); } } else if (body.Method == String_Contains) { string fieldName = GetFieldName((body.Object as MemberExpression).Member); Expression valueExpression = body.Arguments[0]; if (valueExpression is ConstantExpression) { var constantValueExpression = valueExpression as ConstantExpression; var parameter = state.GetNextParameter(); if (constantValueExpression.Type == typeof(string) && constantValueExpression.Value != null) { string value = (string)constantValueExpression.Value; state.Parameters.Add(parameter, "%" + value + "%"); state.Where.AppendFormat(" ( t.[{0}] {1}LIKE @{2} )", fieldName, negative, parameter); } else { throw new NotSupportedException(); } } else { throw new NotSupportedException(); } } else { throw new NotSupportedException(); } }
public void Interpret( MethodCallExpression expression, SqlBuilderState state ) { throw new NotImplementedException( string.Format( "DapperLinq does not support the {0}() method", ( expression as MethodCallExpression ).Method.Name ) ); }