Ejemplo n.º 1
0
        internal static bool TryGetIsUnicode(TypeUsage type, out bool isUnicode)
        {
            if (!TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String))
            {
                isUnicode = false;
                return(false);
            }

            return(TypeHelpers.TryGetBooleanFacetValue(type, DbProviderManifest.UnicodeFacetName, out isUnicode));
        }
Ejemplo n.º 2
0
        internal DbFilterExpression(TypeUsage resultType, DbExpressionBinding input, DbExpression predicate)
            : base(DbExpressionKind.Filter, resultType)
        {
            Debug.Assert(input != null, "DbFilterExpression input cannot be null");
            Debug.Assert(predicate != null, "DbBFilterExpression predicate cannot be null");
            Debug.Assert(TypeSemantics.IsPrimitiveType(predicate.ResultType, PrimitiveTypeKind.Boolean), "DbFilterExpression predicate must have a Boolean result type");

            _input     = input;
            _predicate = predicate;
        }
Ejemplo n.º 3
0
 internal static bool SupportsCastToString(TypeUsage typeUsage)
 {
     return(TypeSemantics.IsPrimitiveType(typeUsage, PrimitiveTypeKind.String) ||
            TypeSemantics.IsNumericType(typeUsage) ||
            TypeSemantics.IsBooleanType(typeUsage) ||
            TypeSemantics.IsPrimitiveType(typeUsage, PrimitiveTypeKind.DateTime) ||
            TypeSemantics.IsPrimitiveType(typeUsage, PrimitiveTypeKind.DateTimeOffset) ||
            TypeSemantics.IsPrimitiveType(typeUsage, PrimitiveTypeKind.Time) ||
            TypeSemantics.IsPrimitiveType(typeUsage, PrimitiveTypeKind.Guid));
 }
        internal static bool TryGetScale(TypeUsage type, out byte scale)
        {
            if (!TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Decimal))
            {
                scale = 0;
                return(false);
            }

            return(TryGetByteFacetValue(type, DbProviderManifest.ScaleFacetName, out scale));
        }
Ejemplo n.º 5
0
        internal static bool TryGetPrecision(TypeUsage type, out byte precision)
        {
            if (!TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Decimal))
            {
                precision = 0;
                return(false);
            }

            return(TypeHelpers.TryGetByteFacetValue(type, DbProviderManifest.PrecisionFacetName, out precision));
        }
Ejemplo n.º 6
0
        internal DbQuantifierExpression(DbExpressionKind kind, TypeUsage booleanResultType, DbExpressionBinding input, DbExpression predicate)
            : base(kind, booleanResultType)
        {
            Debug.Assert(input != null, "DbQuantifierExpression input cannot be null");
            Debug.Assert(predicate != null, "DbQuantifierExpression predicate cannot be null");
            Debug.Assert(TypeSemantics.IsPrimitiveType(booleanResultType, PrimitiveTypeKind.Boolean), "DbQuantifierExpression must have a Boolean result type");
            Debug.Assert(TypeSemantics.IsPrimitiveType(predicate.ResultType, PrimitiveTypeKind.Boolean), "DbQuantifierExpression predicate must have a Boolean result type");

            this._input     = input;
            this._predicate = predicate;
        }
Ejemplo n.º 7
0
        internal DbFilterExpression(TypeUsage resultType, DbExpressionBinding input, DbExpression predicate)
            : base(DbExpressionKind.Filter, resultType)
        {
            DebugCheck.NotNull(input);
            DebugCheck.NotNull(predicate);
            Debug.Assert(
                TypeSemantics.IsPrimitiveType(predicate.ResultType, PrimitiveTypeKind.Boolean),
                "DbFilterExpression predicate must have a Boolean result type");

            _input     = input;
            _predicate = predicate;
        }
Ejemplo n.º 8
0
        internal static bool TryGetMaxLength(TypeUsage type, out int maxLength)
        {
            if (!TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String) &&
                !TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Binary))
            {
                maxLength = 0;
                return(false);
            }

            // Binary and String FixedLength facets share the same name
            return(TypeHelpers.TryGetIntFacetValue(type, DbProviderManifest.MaxLengthFacetName, out maxLength));
        }
Ejemplo n.º 9
0
            private static void BuildTypeName(StringBuilder text, TypeUsage type)
            {
                var rowType  = type.EdmType as RowType;
                var collType = type.EdmType as CollectionType;
                var refType  = type.EdmType as RefType;

                if (TypeSemantics.IsPrimitiveType(type))
                {
                    text.Append(type);
                }
                else if (collType != null)
                {
                    text.Append("Collection{");
                    BuildTypeName(text, collType.TypeUsage);
                    text.Append("}");
                }
                else if (refType != null)
                {
                    text.Append("Ref<");
                    AppendFullName(text, refType.ElementType);
                    text.Append(">");
                }
                else if (rowType != null)
                {
                    text.Append("Record[");
                    var idx = 0;
                    foreach (var recColumn in rowType.Properties)
                    {
                        text.Append("'");
                        text.Append(recColumn.Name);
                        text.Append("'");
                        text.Append("=");
                        BuildTypeName(text, recColumn.TypeUsage);
                        idx++;
                        if (idx < rowType.Properties.Count)
                        {
                            text.Append(", ");
                        }
                    }
                    text.Append("]");
                }
                else
                {
                    // Entity, Relationship, Complex
                    if (!string.IsNullOrEmpty(type.EdmType.NamespaceName))
                    {
                        text.Append(type.EdmType.NamespaceName);
                        text.Append(".");
                    }
                    text.Append(type.EdmType.Name);
                }
            }
Ejemplo n.º 10
0
        internal static bool TryGetIsFixedLength(TypeUsage type, out bool isFixedLength)
        {
            if (!TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String)
                &&
                !TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Binary))
            {
                isFixedLength = false;
                return(false);
            }

            // Binary and String MaxLength facets share the same name
            return(TryGetBooleanFacetValue(type, DbProviderManifest.FixedLengthFacetName, out isFixedLength));
        }
Ejemplo n.º 11
0
            private static void BuildTypeName(StringBuilder text, TypeUsage type)
            {
                RowType        edmType1 = type.EdmType as RowType;
                CollectionType edmType2 = type.EdmType as CollectionType;
                RefType        edmType3 = type.EdmType as RefType;

                if (TypeSemantics.IsPrimitiveType(type))
                {
                    text.Append((object)type);
                }
                else if (edmType2 != null)
                {
                    text.Append("Collection{");
                    ExpressionPrinter.PrinterVisitor.BuildTypeName(text, edmType2.TypeUsage);
                    text.Append("}");
                }
                else if (edmType3 != null)
                {
                    text.Append("Ref<");
                    ExpressionPrinter.PrinterVisitor.AppendFullName(text, (EdmType)edmType3.ElementType);
                    text.Append(">");
                }
                else if (edmType1 != null)
                {
                    text.Append("Record[");
                    int num = 0;
                    foreach (EdmProperty property in edmType1.Properties)
                    {
                        text.Append("'");
                        text.Append(property.Name);
                        text.Append("'");
                        text.Append("=");
                        ExpressionPrinter.PrinterVisitor.BuildTypeName(text, property.TypeUsage);
                        ++num;
                        if (num < edmType1.Properties.Count)
                        {
                            text.Append(", ");
                        }
                    }
                    text.Append("]");
                }
                else
                {
                    if (!string.IsNullOrEmpty(type.EdmType.NamespaceName))
                    {
                        text.Append(type.EdmType.NamespaceName);
                        text.Append(".");
                    }
                    text.Append(type.EdmType.Name);
                }
            }
        private static string GetTypeUsageToken(TypeUsage type)
        {
            string result = null;

            // Dev10#537010: EntityCommand false positive cache hits caused by insufficient parameter type information in cache key
            // Ensure String types are correctly differentiated.
            if (ReferenceEquals(type, DbTypeMap.AnsiString))
            {
                result = "AnsiString";
            }
            else if (ReferenceEquals(type, DbTypeMap.AnsiStringFixedLength))
            {
                result = "AnsiStringFixedLength";
            }
            else if (ReferenceEquals(type, DbTypeMap.String))
            {
                result = "String";
            }
            else if (ReferenceEquals(type, DbTypeMap.StringFixedLength))
            {
                result = "StringFixedLength";
            }
            else if (ReferenceEquals(type, DbTypeMap.Xml))
            {
                // Xml is currently mapped to (unicode, variable-length) string, so the TypeUsage
                // given to the provider is actually a String TypeUsage.
                Debug.Assert(
                    TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String),
                    "Update GetTypeUsageToken to return 'Xml' for Xml parameters");
                result = "String";
            }
            else if (TypeSemantics.IsEnumerationType(type))
            {
                result = type.EdmType.FullName;
            }
            else
            {
                // String/Xml TypeUsages are the only DbType-derived TypeUsages that carry meaningful facets.
                // Otherwise, the primitive type name is a sufficient token (note that full name is not required
                // since model types always have the 'Edm' namespace).
                Debug.Assert(TypeSemantics.IsPrimitiveType(type), "EntityParameter TypeUsage not a primitive type?");
                Debug.Assert(
                    !TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String),
                    "String TypeUsage not derived from DbType.AnsiString, AnsiString, String, StringFixedLength or Xml?");
                result = type.EdmType.Name;
            }

            return(result);
        }
        internal DbLikeExpression(TypeUsage booleanResultType, DbExpression input, DbExpression pattern, DbExpression escape)
            : base(DbExpressionKind.Like, booleanResultType)
        {
            Debug.Assert(input != null, "DbLikeExpression argument cannot be null");
            Debug.Assert(pattern != null, "DbLikeExpression pattern cannot be null");
            Debug.Assert(escape != null, "DbLikeExpression escape cannot be null");
            Debug.Assert(TypeSemantics.IsPrimitiveType(input.ResultType, PrimitiveTypeKind.String), "DbLikeExpression argument must have a string result type");
            Debug.Assert(TypeSemantics.IsPrimitiveType(pattern.ResultType, PrimitiveTypeKind.String), "DbLikeExpression pattern must have a string result type");
            Debug.Assert(TypeSemantics.IsPrimitiveType(escape.ResultType, PrimitiveTypeKind.String), "DbLikeExpression escape must have a string result type");
            Debug.Assert(TypeSemantics.IsBooleanType(booleanResultType), "DbLikeExpression must have a Boolean result type");

            this._argument = input;
            this._pattern  = pattern;
            this._escape   = escape;
        }
Ejemplo n.º 14
0
        internal DbLikeExpression(TypeUsage booleanResultType, DbExpression input, DbExpression pattern, DbExpression escape)
            : base(DbExpressionKind.Like, booleanResultType)
        {
            DebugCheck.NotNull(input);
            DebugCheck.NotNull(pattern);
            DebugCheck.NotNull(escape);
            Debug.Assert(
                TypeSemantics.IsPrimitiveType(input.ResultType, PrimitiveTypeKind.String),
                "DbLikeExpression argument must have a string result type");
            Debug.Assert(
                TypeSemantics.IsPrimitiveType(pattern.ResultType, PrimitiveTypeKind.String),
                "DbLikeExpression pattern must have a string result type");
            Debug.Assert(
                TypeSemantics.IsPrimitiveType(escape.ResultType, PrimitiveTypeKind.String),
                "DbLikeExpression escape must have a string result type");
            Debug.Assert(TypeSemantics.IsBooleanType(booleanResultType), "DbLikeExpression must have a Boolean result type");

            _argument = input;
            _pattern  = pattern;
            _escape   = escape;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Adds the flattened properties on the input to the flattenedProperties list.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="flattenedProperties"></param>
        private void FlattenProperties(DbExpression input, IList <DbPropertyExpression> flattenedProperties)
        {
            IList <EdmProperty> properties = TypeHelpers.GetProperties(input.ResultType);

            Debug.Assert(properties.Count != 0, "No nested properties when FlattenProperties called?");

            for (int i = 0; i < properties.Count; i++)
            {
                DbExpression propertyInput = input;

                DbPropertyExpression propertyExpression = propertyInput.Property(properties[i]);
                if (TypeSemantics.IsPrimitiveType(properties[i].TypeUsage))
                {
                    flattenedProperties.Add(propertyExpression);
                }
                else
                {
                    Debug.Assert(TypeSemantics.IsEntityType(properties[i].TypeUsage) || TypeSemantics.IsRowType(properties[i].TypeUsage),
                                 "The input to FlattenProperties is not of EntityType or RowType?");

                    FlattenProperties(propertyExpression, flattenedProperties);
                }
            }
        }
 internal DbNotExpression(TypeUsage booleanResultType, DbExpression argument)
     : base(DbExpressionKind.Not, booleanResultType, argument)
 {
     Debug.Assert(TypeSemantics.IsPrimitiveType(booleanResultType, PrimitiveTypeKind.Boolean), "DbNotExpression requires a Boolean result type");
 }
        protected override void SetDbParameterValue(DbParameter parameter, TypeUsage parameterType, object value)
        {
            // Ensure a value that can be used with SqlParameter
            value = EnsureSqlParameterValue(value);

            if (TypeSemantics.IsPrimitiveType(parameterType, PrimitiveTypeKind.String) ||
                TypeSemantics.IsPrimitiveType(parameterType, PrimitiveTypeKind.Binary))
            {
                int?size = GetParameterSize(parameterType, ((parameter.Direction & ParameterDirection.Output) == ParameterDirection.Output));
                if (!size.HasValue)
                {
                    // Remember the current Size
                    int previousSize = parameter.Size;

                    // Infer the Size from the value
                    parameter.Size  = 0;
                    parameter.Value = value;

                    if (previousSize > -1)
                    {
                        // The 'max' length was chosen as a specific value for the parameter's Size property on Sql8 (4000 or 8000)
                        // because no MaxLength was specified in the TypeUsage and the provider is Sql8.
                        // If the value's length is less than or equal to this preset size, then the Size value can be retained,
                        // otherwise this preset size must be removed in favor of the Size inferred from the value itself.

                        // If the inferred Size is less than the preset 'max' size, restore that preset size
                        if (parameter.Size < previousSize)
                        {
                            parameter.Size = previousSize;
                        }
                    }
                    else
                    {
                        // -1 was chosen as the parameter's size because no MaxLength was specified in the TypeUsage and the
                        // provider is more recent than Sql8. However, it is more optimal to specify a non-max (-1) value for
                        // the size where possible, since 'max' parameters may prevent, for example, filter pushdown.
                        // (see Dev10#617447 for more details)
                        int suggestedLength = GetNonMaxLength(((SqlParameter)parameter).SqlDbType);
                        if (parameter.Size < suggestedLength)
                        {
                            parameter.Size = suggestedLength;
                        }
                        else if (parameter.Size > suggestedLength)
                        {
                            // The parameter size is greater than the suggested length, so the suggested length cannot be used.
                            // Since the provider is Sql9 or newer, set the size to max (-1) instead of the inferred size for better plan reuse.
                            parameter.Size = -1;
                        }
                    }
                }
                else
                {
                    // Just set the value
                    parameter.Value = value;
                }
            }
            else
            {
                // Not a string or binary parameter - just set the value
                parameter.Value = value;
            }
        }
        // <summary>
        // Constructs a SqlCeParameter
        // </summary>
        internal static DbParameter CreateSqlCeParameter(
            string name, TypeUsage type, object value, bool ignoreMaxLengthFacet, bool isLocalProvider)
        {
            var rdpSqlCeParameter = Type.GetType(RemoteProvider.SqlCeParameter);

            // No other parameter type is supported.
            //
            DebugCheck.NotNull(type);

            int? size;
            byte?precision;
            byte?scale;

            var result = isLocalProvider
                             ? new SqlCeParameter()
                             : (DbParameter)RemoteProviderHelper.CreateRemoteProviderType(RemoteProvider.SqlCeParameter);

            result.ParameterName = name;
            result.Value         = value;

            // .Direction
            // parameter.Direction - take the default. we don't support output parameters.
            result.Direction = ParameterDirection.Input;

            // .Size, .Precision, .Scale and .SqlDbType
            var sqlDbType = GetSqlDbType(type, out size, out precision, out scale);

            // Skip guessing the parameter type (only for strings & blobs) if parameter size is not available
            // Instead, let QP take proper guess at execution time with available details.
            //
            if ((null != size) ||
                (!TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.String) &&
                 !TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Binary)))
            {
                if (isLocalProvider)
                {
                    var sqlCeParameter = (SqlCeParameter)result;
                    if (sqlCeParameter.SqlDbType != sqlDbType)
                    {
                        sqlCeParameter.SqlDbType = sqlDbType;
                    }
                }
                else
                {
                    // Remote Provider is loaded by reflection. As SqlDbType is not part of the base interface
                    // We need to access this using reflection only.
                    var rdpType = RemoteProviderHelper.GetRemoteProviderType(RemoteProvider.SqlCeParameter);
                    var rdpInfo = rdpType.GetProperty("SqlDbType");
                    rdpInfo.SetValue(result, sqlDbType, null);
                }
            }

            // Note that we overwrite 'facet' parameters where either the value is different or
            // there is an output parameter. This is because output parameters in SqlClient have their
            // facets clobbered if they are implicitly set (e.g. if the Precision was implicitly set
            // by setting the value)
            if (!ignoreMaxLengthFacet &&
                size.HasValue &&
                (result.Size != size.Value))
            {
                result.Size = size.Value;
            }

            if (precision.HasValue &&
                (((IDbDataParameter)result).Precision != precision.Value))
            {
                ((IDbDataParameter)result).Precision = precision.Value;
            }
            if (scale.HasValue &&
                (((IDbDataParameter)result).Scale != scale.Value))
            {
                ((IDbDataParameter)result).Scale = scale.Value;
            }

            // .IsNullable
            var isNullable = TypeSemantics.IsNullable(type);

            if (isNullable != result.IsNullable)
            {
                result.IsNullable = isNullable;
            }

            return(result);
        }
Ejemplo n.º 19
0
 protected static void AssertBoolean(TypeUsage type)
 {
     Assert(
         TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Boolean), "Type Mismatch: Expected Boolean; found {0} instead",
         type.ToString());
 }
Ejemplo n.º 20
0
        private void WriteFunctionElement(EdmFunction function)
        {
            _writer.WriteStartElement(function.IsFunctionImport ? XmlConstants.FunctionImport : XmlConstants.Function);
            _writer.WriteAttributeString(XmlConstants.Name, function.Name);

            // Write function ReturnType as attribute if possible.
            bool returnParameterHandled = false;

            if (function.ReturnParameter != null)
            {
                var  returnTypeUsage = function.ReturnParameter.TypeUsage;
                bool collection      = returnTypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType;
                if (collection)
                {
                    Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3, "_schemaVersion >= EntityFrameworkVersions.Version3");
                    returnTypeUsage = ((CollectionType)returnTypeUsage.EdmType).TypeUsage;
                }
                if (TypeSemantics.IsPrimitiveType(returnTypeUsage) || TypeSemantics.IsNominalType(returnTypeUsage))
                {
                    string typeName = GetFullName(returnTypeUsage.EdmType);
                    if (collection)
                    {
                        typeName = "Collection(" + typeName + ")";
                    }
                    _writer.WriteAttributeString(XmlConstants.ReturnType, typeName);
                    returnParameterHandled = true;
                }
            }

            if (!_isModel)
            {
                _writer.WriteAttributeString(XmlConstants.AggregateAttribute, GetAttributeValueString(function.AggregateAttribute));
                _writer.WriteAttributeString(XmlConstants.BuiltInAttribute, GetAttributeValueString(function.BuiltInAttribute));
                _writer.WriteAttributeString(XmlConstants.NiladicFunction, GetAttributeValueString(function.NiladicFunctionAttribute));
                _writer.WriteAttributeString(XmlConstants.IsComposable, GetAttributeValueString(function.IsComposableAttribute));
                _writer.WriteAttributeString(XmlConstants.ParameterTypeSemantics, GetAttributeValueString(function.ParameterTypeSemanticsAttribute));
            }
            else if (function.IsFunctionImport && function.IsComposableAttribute)
            {
                Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3, "_schemaVersion >= EntityFrameworkVersions.Version3");
                _writer.WriteAttributeString(XmlConstants.IsComposable, GetAttributeValueString(true));
            }

            if (function.StoreFunctionNameAttribute != null)
            {
                _writer.WriteAttributeString(XmlConstants.StoreFunctionName, function.StoreFunctionNameAttribute);
            }

            if (function.CommandTextAttribute != null)
            {
                Debug.Assert(!_isModel, "Serialization of CommandTextAttribute is not supported for CSDL.");
                _writer.WriteAttributeString(XmlConstants.CommandText, function.CommandTextAttribute);
            }

            if (function.Schema != null)
            {
                _writer.WriteAttributeString(XmlConstants.Schema, function.Schema);
            }

            foreach (FunctionParameter parameter in function.Parameters)
            {
                WriteFunctionParameterElement(parameter);
            }

            // Write function ReturnType subelement if needed.
            if (function.ReturnParameter != null && !returnParameterHandled)
            {
                // Handle a TVF in s-space: Collection(RowType)
                if (function.ReturnParameter.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
                {
                    Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3 && !_isModel, "_schemaVersion >= EntityFrameworkVersions.Version3 && !_isModel");
                    var elementType = ((CollectionType)function.ReturnParameter.TypeUsage.EdmType).TypeUsage.EdmType;
                    Debug.Assert(elementType.BuiltInTypeKind == BuiltInTypeKind.RowType, "TVF return type is expected to be Collection(RowType)");
                    var rowType = (RowType)elementType;
                    _writer.WriteStartElement(XmlConstants.ReturnType);
                    _writer.WriteStartElement(XmlConstants.CollectionType);
                    WriteTypeElement(rowType);
                    _writer.WriteEndElement();
                    _writer.WriteEndElement();
                    returnParameterHandled = true;
                }
            }

            Debug.Assert(function.ReturnParameter == null || returnParameterHandled, "ReturnParameter was not handled.");
            _writer.WriteEndElement();
        }
Ejemplo n.º 21
0
 protected static void AssertBoolean(TypeUsage type)
 {
     Assert(TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Boolean), "Type Mismatch: Expected Boolean; found {0} instead", TypeHelpers.GetFullName(type));
 }
Ejemplo n.º 22
0
 internal DbOrExpression(TypeUsage booleanResultType, DbExpression left, DbExpression right)
     : base(DbExpressionKind.Or, booleanResultType, left, right)
 {
     Debug.Assert(
         TypeSemantics.IsPrimitiveType(booleanResultType, PrimitiveTypeKind.Boolean), "DbOrExpression requires a Boolean result type");
 }
Ejemplo n.º 23
0
            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)))));
                }
            }