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))));
}
}