private string IncludeAlias(Data.ConditionCollection cc, MemberExpression lExp, string alias) { var innerExp = lExp.Expression as MemberExpression; if (innerExp != null) { alias = IncludeAlias(cc, innerExp, alias); } string newAlias = lExp.Member.Name.ToLower() + random.Next(1000, 9999).ToString(); cc.Include(alias, lExp.Member.Name, newAlias, Data.JoinMode.LeftJoin); return(newAlias); }
private void ReadWhereExpressions(Tenor.Data.ConditionCollection cc, Expression ex, bool not, string alias) { switch (ex.NodeType) { case ExpressionType.Quote: { UnaryExpression une = ex as UnaryExpression; if (une.IsLifted || une.IsLiftedToNull) { throw new NotImplementedException(); } ReadWhereExpressions(cc, une.Operand, not, alias); } break; case ExpressionType.Lambda: { LambdaExpression lex = ex as LambdaExpression; //TODO: Should we check parameters? ReadWhereExpressions(cc, lex.Body, not, alias); } break; case ExpressionType.Not: { UnaryExpression une = ex as UnaryExpression; if (une.IsLifted || une.IsLiftedToNull) { throw new NotImplementedException(); } ReadWhereExpressions(cc, une.Operand, !not, alias); } break; case ExpressionType.And: case ExpressionType.AndAlso: { BinaryExpression andBinary = ex as BinaryExpression; Tenor.Data.ConditionCollection newCc = new Tenor.Data.ConditionCollection(); ReadWhereExpressions(newCc, andBinary.Left, not, alias); newCc.Add(Tenor.Data.LogicalOperator.And); ReadWhereExpressions(newCc, andBinary.Right, not, alias); if (cc.Count > 0 && cc[cc.Count - 1].GetType() != typeof(Tenor.Data.LogicalOperator)) { cc.Add(Tenor.Data.LogicalOperator.And); } cc.Add(newCc); } break; case ExpressionType.Or: case ExpressionType.OrElse: { BinaryExpression andBinary = ex as BinaryExpression; Tenor.Data.ConditionCollection newCc = new Tenor.Data.ConditionCollection(); ReadWhereExpressions(newCc, andBinary.Left, not, alias); newCc.Add(Tenor.Data.LogicalOperator.Or); ReadWhereExpressions(newCc, andBinary.Right, not, alias); if (cc.Count > 0 && cc[cc.Count - 1].GetType() != typeof(Tenor.Data.LogicalOperator)) { cc.Add(Tenor.Data.LogicalOperator.And); } cc.Add(newCc); } break; case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: { BinaryExpression bex = ex as BinaryExpression; bool lower = false, upper = false; if (bex.Left.NodeType == ExpressionType.Call) { var call = (bex.Left as MethodCallExpression); lower = (call.Method.Name == "ToLower"); upper = (call.Method.Name == "ToUpper"); } MemberExpression left = ReadOperand(bex, false) as MemberExpression; bool invertOperator = false; Expression right = ReadOperand(bex, true, ref invertOperator); if (ex.NodeType != ExpressionType.Equal && ex.NodeType != ExpressionType.NotEqual && invertOperator) { not = !not; } //check if we need another alias if (left.Expression != null && left.Expression is MemberExpression) { MemberExpression lExp = (MemberExpression)left.Expression; if (lExp.Member.MemberType == MemberTypes.Property) { alias = IncludeAlias(cc, lExp, alias); } } Tenor.Data.CompareOperator op = Tenor.Data.CompareOperator.Equal; if (ex.NodeType == ExpressionType.Equal && !not) { op = Tenor.Data.CompareOperator.Equal; } else if (ex.NodeType == ExpressionType.Equal && not) { op = Tenor.Data.CompareOperator.NotEqual; } else if (ex.NodeType == ExpressionType.NotEqual && !not) { op = Tenor.Data.CompareOperator.NotEqual; } else if (ex.NodeType == ExpressionType.NotEqual && not) { op = Tenor.Data.CompareOperator.Equal; } else if (ex.NodeType == ExpressionType.GreaterThan && !not) { op = Tenor.Data.CompareOperator.GreaterThan; } else if (ex.NodeType == ExpressionType.GreaterThan && not) { op = Tenor.Data.CompareOperator.LessThan; } else if (ex.NodeType == ExpressionType.LessThan && !not) { op = Tenor.Data.CompareOperator.LessThan; } else if (ex.NodeType == ExpressionType.LessThan && not) { op = Tenor.Data.CompareOperator.GreaterThan; } else if (ex.NodeType == ExpressionType.GreaterThanOrEqual && !not) { op = Tenor.Data.CompareOperator.GreaterThanOrEqual; } else if (ex.NodeType == ExpressionType.GreaterThanOrEqual && not) { op = Tenor.Data.CompareOperator.LessThanOrEqual; } else if (ex.NodeType == ExpressionType.LessThanOrEqual && !not) { op = Tenor.Data.CompareOperator.LessThanOrEqual; } else if (ex.NodeType == ExpressionType.LessThanOrEqual && not) { op = Tenor.Data.CompareOperator.GreaterThanOrEqual; } if (op == Data.CompareOperator.Equal) { if (upper) { op = Tenor.Data.CompareOperator.EqualUpper; } else if (lower) { op = Tenor.Data.CompareOperator.EqualLower; } } else if (op == Data.CompareOperator.NotEqual) { if (upper) { op = Tenor.Data.CompareOperator.NotEqualUpper; } else if (lower) { op = Tenor.Data.CompareOperator.NotEqualLower; } } if (cc.Count > 0 && !(cc[cc.Count - 1] is Tenor.Data.LogicalOperator)) { cc.Add(Data.LogicalOperator.And); } cc.Add(left.Member.Name, FindValue(right), op, alias); } break; case ExpressionType.MemberAccess: { MemberExpression mex = ex as MemberExpression; if (mex.Type != typeof(bool) && (!mex.Type.IsGenericType || mex.Type != typeof(bool?))) { throw new InvalidOperationException("Invalid lambda expression"); } Tenor.Data.CompareOperator op = Tenor.Data.CompareOperator.Equal; if (not) { op = Tenor.Data.CompareOperator.NotEqual; } if (cc.Count > 0 && cc[cc.Count - 1].GetType() != typeof(Tenor.Data.LogicalOperator)) { cc.Add(Tenor.Data.LogicalOperator.And); } cc.Add(mex.Member.Name, true, op, alias); } break; case ExpressionType.Call: { MethodCallExpression mce = (MethodCallExpression)ex; switch (mce.Method.Name) { case "Contains": case "StartsWith": case "EndsWith": { MemberExpression member = (mce.Object != null ? mce.Object : mce.Arguments[0]) as MemberExpression; MemberExpression property = (mce.Object != null ? mce.Arguments[0] : mce.Arguments[1]) as MemberExpression; MethodCallExpression methodCall = (mce.Object != null ? mce.Arguments[0] : mce.Arguments[1]) as MethodCallExpression; if (mce.Method.Name == "Contains" && member.Type != typeof(string)) { // In Tenor.Data.ConditionCollection inValues = new Data.ConditionCollection(); IList list = FindValue(member) as IList; foreach (object v in list) { if (inValues.Count > 0) { inValues.Add(Data.LogicalOperator.Or); } inValues.Add(property.Member.Name, v, Data.CompareOperator.Equal, alias); } if (inValues.Count > 0) { cc.Add(inValues); } } else if (member.Type == typeof(string)) { //this will generate a like expression string str = property != null? FindValue(property) as string : FindValue(methodCall) as string; if (mce.Method.Name == "StartsWith") { str = string.Format("{0}%", str); } else if (mce.Method.Name == "EndsWith") { str = string.Format("%{0}", str); } else if (mce.Method.Name == "Contains") { str = string.Format("%{0}%", str); } Tenor.Data.CompareOperator op = Tenor.Data.CompareOperator.Like; if (not) { op = Tenor.Data.CompareOperator.NotLike; } cc.Add(member.Member.Name, str, op, alias); } else { throw new NotImplementedException(string.Format("{0} not implemented with current parameters.", mce.Method.Name)); } } break; case "Any": { //here we will join. MemberExpression member = mce.Arguments[0] as MemberExpression; string newAlias = GenerateAliasForMember(alias, member); Tenor.Data.ConditionCollection newCc = new Tenor.Data.ConditionCollection(); ReadWhereExpressions(newCc, mce.Arguments[1], not, newAlias); if (cc.Count > 0 && cc[cc.Count - 1].GetType() != typeof(Tenor.Data.LogicalOperator)) { cc.Add(Tenor.Data.LogicalOperator.And); } cc.Add(newCc); } break; default: throw new NotImplementedException("Linq method call to '" + mce.Method.Name + "' is not implemented. Please, send a feature request."); } } break; default: throw new NotImplementedException("Linq '" + ex.NodeType.ToString() + "' is not implemented. Please, send a feature request."); } }