protected override Expression VisitMethodCall(MethodCallExpression node) { string prefix = (futureComparisons.TryPop(out string literalCompare) && literalCompare == "= 'False'") ? "NOT " : ""; using var mc = log?.Enter(LogLevel.LinqExpression, node); // member.Contains(...) || member.StartsWith(...) if (node.Method.DeclaringType == typeof(string) && (node.Method.Name == nameof(string.StartsWith) || node.Method.Name == nameof(string.Contains))) { foreach (var prop in TypeProperties.Where(prop => prop.PropertyType == typeof(string))) { if (ExpressionTreeHelpers.IsSpecificMemberExpression(node.Object, typeof(T), prop.Name)) { object testValue = TranslateValue(prop, ExpressionTreeHelpers.GetValueFromExpression(node.Arguments[0])); AddClause($"{prefix}[{TranslateFieldName(prop)}] CONTAINS '{testValue}' "); return(node); } } } // array.Contains(member) || List<string>.Contains(member) else if (node.Method.Name == nameof(string.Contains)) { PropertyInfo propertyInfo = null; Expression valuesExpression = null; if (node.Method.DeclaringType == typeof(Enumerable)) { foreach (var prop in TypeProperties) { if (ExpressionTreeHelpers.IsSpecificMemberExpression(node.Arguments[0], typeof(T), prop.Name)) { propertyInfo = prop; valuesExpression = node.Arguments[1]; break; } else if (ExpressionTreeHelpers.IsSpecificMemberExpression(node.Arguments[1], typeof(T), prop.Name)) { propertyInfo = prop; valuesExpression = node.Arguments[0]; break; } } } else if (node.Method.DeclaringType == typeof(List <string>)) { foreach (var prop in TypeProperties) { if (ExpressionTreeHelpers.IsSpecificMemberExpression(node.Arguments[0], typeof(T), prop.Name)) { propertyInfo = prop; valuesExpression = node.Object; break; } if (ExpressionTreeHelpers.IsSpecificMemberExpression(node.Object, typeof(T), prop.Name)) { propertyInfo = prop; valuesExpression = node.Arguments[0]; break; } } } else { throw new Exception($"{node.Method.DeclaringType} must be Enumerable or List<string> to use 'Contains'"); } if (valuesExpression == null || valuesExpression.NodeType != ExpressionType.Constant) { throw new Exception($"'Contains' expression must compare to a set of literals - {valuesExpression?.NodeType}"); } ConstantExpression ce = (ConstantExpression)valuesExpression; if (ce.Value is string text) // single value { AddClause($"{prefix}[{TranslateFieldName(propertyInfo)}] CONTAINS '{ce.Value}' "); } else { // Add each string in the collection to the list of locations to obtain data about. var textValues = (IEnumerable <string>)ce.Value; AddClause($"{prefix}[{TranslateFieldName(propertyInfo)}] IN ({string.Join(',', textValues.Select(s => "'" + s + "'"))}) "); } return(node); } return(base.VisitMethodCall(node)); }