internal static DbExpression ConvertToString(ExpressionConverter parent, LinqExpression linqExpression) { if (linqExpression.Type == typeof(object)) { var constantExpression = linqExpression as ConstantExpression; linqExpression = constantExpression != null ? Expression.Constant(constantExpression.Value) : linqExpression.RemoveConvert(); } var expression = parent.TranslateExpression(linqExpression); var clrType = TypeSystem.GetNonNullableType(linqExpression.Type); if (clrType.IsEnum) { //Flag enums are not supported. if (Attribute.IsDefined(clrType, typeof(FlagsAttribute))) { throw new NotSupportedException(Strings.Elinq_ToStringNotSupportedForEnumsWithFlags); } if (linqExpression.IsNullConstant()) { return DbExpressionBuilder.Constant(string.Empty); } //Constant expression, optimize to constant name if (linqExpression.NodeType == ExpressionType.Constant) { var value = ((ConstantExpression)linqExpression).Value; var name = Enum.GetName(clrType, value) ?? value.ToString(); return DbExpressionBuilder.Constant(name); } var integralType = clrType.GetEnumUnderlyingType(); var type = parent.GetValueLayerType(integralType); var values = clrType.GetEnumValues() .Cast<object>() .Select(v => System.Convert.ChangeType(v, integralType, CultureInfo.InvariantCulture)) //cast to integral type so that unmapped enum types works too .Select(v => DbExpressionBuilder.Constant(v)) .Select(c => (DbExpression)expression.CastTo(type).Equal(c)) //cast expression to integral type before comparing to constant .Concat(new[] { expression.CastTo(type).IsNull() }); // default case var names = clrType.GetEnumNames() .Select(s => DbExpressionBuilder.Constant(s)) .Concat(new[] { DbExpressionBuilder.Constant(string.Empty) }); // default case //translate unnamed enum values for the else clause, raw linq -> as integral value -> translate to cqt -> to string //e.g. ((DayOfWeek)99) -> "99" var asIntegralLinq = LinqExpression.Convert(linqExpression, integralType); var asStringCqt = parent .TranslateExpression(asIntegralLinq) .CastTo(parent.GetValueLayerType(typeof(string))); return DbExpressionBuilder.Case(values, names, asStringCqt); } else if (TypeSemantics.IsPrimitiveType(expression.ResultType, PrimitiveTypeKind.String)) { return StripNull(linqExpression, expression, expression); } else if (TypeSemantics.IsPrimitiveType(expression.ResultType, PrimitiveTypeKind.Guid)) { return StripNull(linqExpression, expression, expression.CastTo(parent.GetValueLayerType(typeof(string))).ToLower()); } else if (TypeSemantics.IsPrimitiveType(expression.ResultType, PrimitiveTypeKind.Boolean)) { if (linqExpression.IsNullConstant()) { return DbExpressionBuilder.Constant(string.Empty); } if (linqExpression.NodeType == ExpressionType.Constant) { var name = ((ConstantExpression)linqExpression).Value.ToString(); return DbExpressionBuilder.Constant(name); } var whenTrue = expression.Equal(DbExpressionBuilder.True); var whenFalse = expression.Equal(DbExpressionBuilder.False); var thenTrue = DbExpressionBuilder.Constant(true.ToString()); var thenFalse = DbExpressionBuilder.Constant(false.ToString()); return DbExpressionBuilder.Case( new[] { whenTrue, whenFalse }, new[] { thenTrue, thenFalse }, DbExpressionBuilder.Constant(string.Empty)); } else { if (!SupportsCastToString(expression.ResultType)) { throw new NotSupportedException( Strings.Elinq_ToStringNotSupportedForType(expression.ResultType.EdmType.Name)); } //treat all other types as a simple cast return StripNull(linqExpression, expression, expression.CastTo(parent.GetValueLayerType(typeof(string)))); } }