Пример #1
0
        // <summary>
        // Creates generated view object for the combination of the <paramref name="extent" /> and the <paramref name="type" />.
        // This constructor is used for regular cell-based view generation.
        // </summary>
        internal static GeneratedView CreateGeneratedView(
            EntitySetBase extent,
            EdmType type,
            DbQueryCommandTree commandTree,
            string eSQL,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config)
        {
            // If config.GenerateEsql is specified, eSQL must be non-null.
            // If config.GenerateEsql is false, commandTree is non-null except the case when loading pre-compiled eSQL views.
            Debug.Assert(!config.GenerateEsql || !String.IsNullOrEmpty(eSQL), "eSQL must be specified");

            DiscriminatorMap discriminatorMap = null;

            if (commandTree != null)
            {
                commandTree = ViewSimplifier.SimplifyView(extent, commandTree);

                // See if the view matches the "discriminated" pattern (allows simplification of generated store commands)
                if (extent.BuiltInTypeKind
                    == BuiltInTypeKind.EntitySet)
                {
                    if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap))
                    {
                        Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created");
                    }
                }
            }

            return(new GeneratedView(extent, type, commandTree, eSQL, discriminatorMap, mappingItemCollection, config));
        }
 internal ExplicitDiscriminatorMap(DiscriminatorMap template)
 {
     m_typeMap = template.TypeMap;
     m_discriminatorProperty = template.Discriminator.Property;
     m_properties = new ReadOnlyCollection<EdmProperty>(template.PropertyMap.Select(propertyValuePair => propertyValuePair.Key)
                            .ToList());
 }
Пример #3
0
        private GeneratedView(
            EntitySetBase extent,
            EdmType type,
            DbQueryCommandTree commandTree,
            string eSQL,
            DiscriminatorMap discriminatorMap,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config)
        {
            this.m_extent                = extent;
            this.m_type                  = type;
            this.m_commandTree           = commandTree;
            this.m_eSQL                  = eSQL;
            this.m_discriminatorMap      = discriminatorMap;
            this.m_mappingItemCollection = mappingItemCollection;
            this.m_config                = config;
            if (!this.m_config.IsViewTracing)
            {
                return;
            }
            StringBuilder builder = new StringBuilder(1024);

            this.ToCompactString(builder);
            Helpers.FormatTraceLine("CQL view for {0}", (object)builder.ToString());
        }
Пример #4
0
        private GeneratedView(
            EntitySetBase extent,
            EdmType type,
            DbQueryCommandTree commandTree,
            string eSQL,
            DiscriminatorMap discriminatorMap,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config)
        {
            // At least one of the commandTree or eSQL must be specified.
            // Both are specified in the case of user-defined views.
            Debug.Assert(commandTree != null || !String.IsNullOrEmpty(eSQL), "commandTree or eSQL must be specified");

            m_extent                = extent;
            m_type                  = type;
            m_commandTree           = commandTree;
            m_eSQL                  = eSQL;
            m_discriminatorMap      = discriminatorMap;
            m_mappingItemCollection = mappingItemCollection;
            m_config                = config;

            if (m_config.IsViewTracing)
            {
                var trace = new StringBuilder(1024);
                ToCompactString(trace);
                Helpers.FormatTraceLine("CQL view for {0}", trace.ToString());
            }
        }
 internal ExplicitDiscriminatorMap(DiscriminatorMap template)
 {
     m_typeMap = template.TypeMap;
     m_discriminatorProperty = template.Discriminator.Property;
     m_properties = template.PropertyMap.Select(propertyValuePair => propertyValuePair.Key)
         .ToList().AsReadOnly();
 }
        private static bool ExpressionsCompatible(DbExpression x, DbExpression y)
        {
            if (x.ExpressionKind != y.ExpressionKind)
            {
                return(false);
            }
            switch (x.ExpressionKind)
            {
            case DbExpressionKind.NewInstance:
                DbNewInstanceExpression instanceExpression1 = (DbNewInstanceExpression)x;
                DbNewInstanceExpression instanceExpression2 = (DbNewInstanceExpression)y;
                if (!instanceExpression1.ResultType.EdmType.EdmEquals((MetadataItem)instanceExpression2.ResultType.EdmType))
                {
                    return(false);
                }
                for (int index = 0; index < instanceExpression1.Arguments.Count; ++index)
                {
                    if (!DiscriminatorMap.ExpressionsCompatible(instanceExpression1.Arguments[index], instanceExpression2.Arguments[index]))
                    {
                        return(false);
                    }
                }
                return(true);

            case DbExpressionKind.Property:
                DbPropertyExpression propertyExpression1 = (DbPropertyExpression)x;
                DbPropertyExpression propertyExpression2 = (DbPropertyExpression)y;
                if (propertyExpression1.Property == propertyExpression2.Property)
                {
                    return(DiscriminatorMap.ExpressionsCompatible(propertyExpression1.Instance, propertyExpression2.Instance));
                }
                return(false);

            case DbExpressionKind.Ref:
                DbRefExpression dbRefExpression1 = (DbRefExpression)x;
                DbRefExpression dbRefExpression2 = (DbRefExpression)y;
                if (dbRefExpression1.EntitySet.EdmEquals((MetadataItem)dbRefExpression2.EntitySet))
                {
                    return(DiscriminatorMap.ExpressionsCompatible(dbRefExpression1.Argument, dbRefExpression2.Argument));
                }
                return(false);

            case DbExpressionKind.VariableReference:
                return(((DbVariableReferenceExpression)x).VariableName == ((DbVariableReferenceExpression)y).VariableName);

            default:
                return(false);
            }
        }
Пример #7
0
 private static bool TryParseView(
     string eSQL,
     bool isUserSpecified,
     EntitySetBase extent,
     StorageMappingItemCollection mappingItemCollection,
     ConfigViewGenerator config,
     out DbQueryCommandTree commandTree,
     out DiscriminatorMap discriminatorMap,
     out Exception parserException)
 {
     commandTree      = (DbQueryCommandTree)null;
     discriminatorMap = (DiscriminatorMap)null;
     parserException  = (Exception)null;
     config.StartSingleWatch(PerfType.ViewParsing);
     try
     {
         ParserOptions.CompilationMode compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode;
         if (isUserSpecified)
         {
             compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode;
         }
         commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode);
         commandTree = ViewSimplifier.SimplifyView(extent, commandTree);
         if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet)
         {
             DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap);
         }
     }
     catch (Exception ex)
     {
         if (ex.IsCatchableExceptionType())
         {
             parserException = ex;
         }
         else
         {
             throw;
         }
     }
     finally
     {
         config.StopSingleWatch(PerfType.ViewParsing);
     }
     return(parserException == null);
 }
Пример #8
0
        internal static GeneratedView CreateGeneratedView(
            EntitySetBase extent,
            EdmType type,
            DbQueryCommandTree commandTree,
            string eSQL,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config)
        {
            DiscriminatorMap discriminatorMap = (DiscriminatorMap)null;

            if (commandTree != null)
            {
                commandTree = ViewSimplifier.SimplifyView(extent, commandTree);
                if (extent.BuiltInTypeKind == BuiltInTypeKind.EntitySet)
                {
                    DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap);
                }
            }
            return(new GeneratedView(extent, type, commandTree, eSQL, discriminatorMap, mappingItemCollection, config));
        }
        /// <summary>
        /// Determines whether the given query view matches the discriminator map pattern.
        /// </summary>
        internal static bool TryCreateDiscriminatorMap(EntitySet entitySet, DbExpression queryView, out DiscriminatorMap discriminatorMap)
        {
            discriminatorMap = null;

            if (queryView.ExpressionKind
                != DbExpressionKind.Project)
            {
                return false;
            }
            var project = (DbProjectExpression)queryView;

            if (project.Projection.ExpressionKind
                != DbExpressionKind.Case)
            {
                return false;
            }
            var caseExpression = (DbCaseExpression)project.Projection;
            if (project.Projection.ResultType.EdmType.BuiltInTypeKind
                != BuiltInTypeKind.EntityType)
            {
                return false;
            }

            // determine value domain by walking filter
            if (project.Input.Expression.ExpressionKind
                != DbExpressionKind.Filter)
            {
                return false;
            }
            var filterExpression = (DbFilterExpression)project.Input.Expression;

            var discriminatorDomain = new HashSet<object>();
            if (
                !ViewSimplifier.TryMatchDiscriminatorPredicate(
                    filterExpression, (equalsExp, discriminatorValue) => discriminatorDomain.Add(discriminatorValue)))
            {
                return false;
            }

            var typeMap = new List<KeyValuePair<object, EntityType>>();
            var propertyMap = new Dictionary<EdmProperty, DbExpression>();
            var relPropertyMap = new Dictionary<RelProperty, DbExpression>();
            var typeToRelPropertyMap = new Dictionary<EntityType, List<RelProperty>>();
            DbPropertyExpression discriminator = null;

            EdmProperty discriminatorProperty = null;
            for (var i = 0; i < caseExpression.When.Count; i++)
            {
                var when = caseExpression.When[i];
                var then = caseExpression.Then[i];

                var projectionVariableName = project.Input.VariableName;

                DbPropertyExpression currentDiscriminator;
                object discriminatorValue;
                if (
                    !ViewSimplifier.TryMatchPropertyEqualsValue(
                        when, projectionVariableName, out currentDiscriminator, out discriminatorValue))
                {
                    return false;
                }

                // must be the same discriminator in every case
                if (null == discriminatorProperty)
                {
                    discriminatorProperty = (EdmProperty)currentDiscriminator.Property;
                }
                else if (discriminatorProperty != currentDiscriminator.Property)
                {
                    return false;
                }
                discriminator = currentDiscriminator;

                // right hand side must be entity type constructor
                EntityType currentType;
                if (!TryMatchEntityTypeConstructor(then, propertyMap, relPropertyMap, typeToRelPropertyMap, out currentType))
                {
                    return false;
                }

                // remember type + discriminator value
                typeMap.Add(new KeyValuePair<object, EntityType>(discriminatorValue, currentType));

                // remove discriminator value from domain
                discriminatorDomain.Remove(discriminatorValue);
            }

            // make sure only one member of discriminator domain remains...
            if (1 != discriminatorDomain.Count)
            {
                return false;
            }

            // check default case
            EntityType elseType;
            if (null == caseExpression.Else
                ||
                !TryMatchEntityTypeConstructor(caseExpression.Else, propertyMap, relPropertyMap, typeToRelPropertyMap, out elseType))
            {
                return false;
            }
            typeMap.Add(new KeyValuePair<object, EntityType>(discriminatorDomain.Single(), elseType));

            // Account for cases where some type in the hierarchy specifies a rel-property, but another
            // type in the hierarchy does not
            if (!CheckForMissingRelProperties(relPropertyMap, typeToRelPropertyMap))
            {
                return false;
            }

            // since the store may right-pad strings, ensure discriminator values are unique in their trimmed
            // form
            var discriminatorValues = typeMap.Select(map => map.Key);
            var uniqueValueCount = discriminatorValues.Distinct(TrailingSpaceComparer.Instance).Count();
            var valueCount = typeMap.Count;
            if (uniqueValueCount != valueCount)
            {
                return false;
            }

            discriminatorMap = new DiscriminatorMap(discriminator, typeMap, propertyMap, relPropertyMap, entitySet);
            return true;
        }
Пример #10
0
        // <summary>
        // Given an extent and its corresponding view, invokes the parser to check if the view definition is syntactically correct.
        // Iff parsing succeeds: <paramref name="commandTree" /> and <paramref name="discriminatorMap" /> are set to the parse result and method returns true,
        // otherwise if parser has thrown a catchable exception, it is returned via <paramref name="parserException" /> parameter,
        // otherwise exception is re-thrown.
        // </summary>
        private static bool TryParseView(
            string eSQL,
            bool isUserSpecified,
            EntitySetBase extent,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config,
            out DbQueryCommandTree commandTree,
            out DiscriminatorMap discriminatorMap,
            out Exception parserException)
        {
            commandTree      = null;
            discriminatorMap = null;
            parserException  = null;

            // We do not catch any internal exceptions any more
            config.StartSingleWatch(PerfType.ViewParsing);
            try
            {
                // If it is a user specified view, allow all queries. Otherwise parse the view in the restricted mode.
                var compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode;
                if (isUserSpecified)
                {
                    compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode;
                }

                Debug.Assert(!String.IsNullOrEmpty(eSQL), "eSQL query is not specified");
                commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode);

                commandTree = ViewSimplifier.SimplifyView(extent, commandTree);

                // See if the view matches the "discriminated" pattern (allows simplification of generated store commands)
                if (extent.BuiltInTypeKind
                    == BuiltInTypeKind.EntitySet)
                {
                    if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap))
                    {
                        Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created");
                    }
                }
            }
            catch (Exception e)
            {
                // Catching all the exception types since Query parser seems to be throwing a variety of
                // exceptions - EntityException, ArgumentException, ArgumentNullException etc.
                if (e.IsCatchableExceptionType())
                {
                    parserException = e;
                }
                else
                {
                    throw;
                }
            }
            finally
            {
                config.StopSingleWatch(PerfType.ViewParsing);
            }

            Debug.Assert(commandTree != null || parserException != null, "Either commandTree or parserException is expected.");
            // Note: m_commandTree might have been initialized by a previous call to this method, so in consequent calls it might occur that
            // both m_commandTree and parserException are not null - this would mean that the last parse attempt failed, but m_commandTree value is
            // preserved from the previous call.

            return(parserException == null);
        }
Пример #11
0
        // <summary>
        // Determines whether the given query view matches the discriminator map pattern.
        // </summary>
        internal static bool TryCreateDiscriminatorMap(EntitySet entitySet, DbExpression queryView, out DiscriminatorMap discriminatorMap)
        {
            discriminatorMap = null;

            if (queryView.ExpressionKind
                != DbExpressionKind.Project)
            {
                return(false);
            }
            var project = (DbProjectExpression)queryView;

            if (project.Projection.ExpressionKind
                != DbExpressionKind.Case)
            {
                return(false);
            }
            var caseExpression = (DbCaseExpression)project.Projection;

            if (project.Projection.ResultType.EdmType.BuiltInTypeKind
                != BuiltInTypeKind.EntityType)
            {
                return(false);
            }

            // determine value domain by walking filter
            if (project.Input.Expression.ExpressionKind
                != DbExpressionKind.Filter)
            {
                return(false);
            }
            var filterExpression = (DbFilterExpression)project.Input.Expression;

            var discriminatorDomain = new HashSet <object>();

            if (
                !ViewSimplifier.TryMatchDiscriminatorPredicate(
                    filterExpression, (equalsExp, discriminatorValue) => discriminatorDomain.Add(discriminatorValue)))
            {
                return(false);
            }

            var typeMap                        = new List <KeyValuePair <object, EntityType> >();
            var propertyMap                    = new Dictionary <EdmProperty, DbExpression>();
            var relPropertyMap                 = new Dictionary <RelProperty, DbExpression>();
            var typeToRelPropertyMap           = new Dictionary <EntityType, List <RelProperty> >();
            DbPropertyExpression discriminator = null;

            EdmProperty discriminatorProperty = null;

            for (var i = 0; i < caseExpression.When.Count; i++)
            {
                var when = caseExpression.When[i];
                var then = caseExpression.Then[i];

                var projectionVariableName = project.Input.VariableName;

                DbPropertyExpression currentDiscriminator;
                object discriminatorValue;
                if (
                    !ViewSimplifier.TryMatchPropertyEqualsValue(
                        when, projectionVariableName, out currentDiscriminator, out discriminatorValue))
                {
                    return(false);
                }

                // must be the same discriminator in every case
                if (null == discriminatorProperty)
                {
                    discriminatorProperty = (EdmProperty)currentDiscriminator.Property;
                }
                else if (discriminatorProperty != currentDiscriminator.Property)
                {
                    return(false);
                }
                discriminator = currentDiscriminator;

                // right hand side must be entity type constructor
                EntityType currentType;
                if (!TryMatchEntityTypeConstructor(then, propertyMap, relPropertyMap, typeToRelPropertyMap, out currentType))
                {
                    return(false);
                }

                // remember type + discriminator value
                typeMap.Add(new KeyValuePair <object, EntityType>(discriminatorValue, currentType));

                // remove discriminator value from domain
                discriminatorDomain.Remove(discriminatorValue);
            }

            // make sure only one member of discriminator domain remains...
            if (1 != discriminatorDomain.Count)
            {
                return(false);
            }

            // check default case
            EntityType elseType;

            if (null == caseExpression.Else
                ||
                !TryMatchEntityTypeConstructor(caseExpression.Else, propertyMap, relPropertyMap, typeToRelPropertyMap, out elseType))
            {
                return(false);
            }
            typeMap.Add(new KeyValuePair <object, EntityType>(discriminatorDomain.Single(), elseType));

            // Account for cases where some type in the hierarchy specifies a rel-property, but another
            // type in the hierarchy does not
            if (!CheckForMissingRelProperties(relPropertyMap, typeToRelPropertyMap))
            {
                return(false);
            }

            // since the store may right-pad strings, ensure discriminator values are unique in their trimmed
            // form
            var discriminatorValues = typeMap.Select(map => map.Key);
            var uniqueValueCount    = discriminatorValues.Distinct(TrailingSpaceComparer.Instance).Count();
            var valueCount          = typeMap.Count;

            if (uniqueValueCount != valueCount)
            {
                return(false);
            }

            discriminatorMap = new DiscriminatorMap(discriminator, typeMap, propertyMap, relPropertyMap, entitySet);
            return(true);
        }
        private static bool TryMatchEntityTypeConstructor(
            DbExpression then,
            Dictionary <EdmProperty, DbExpression> propertyMap,
            Dictionary <RelProperty, DbExpression> relPropertyMap,
            Dictionary <EntityType, List <RelProperty> > typeToRelPropertyMap,
            out EntityType entityType)
        {
            if (then.ExpressionKind != DbExpressionKind.NewInstance)
            {
                entityType = (EntityType)null;
                return(false);
            }
            DbNewInstanceExpression instanceExpression = (DbNewInstanceExpression)then;

            entityType = (EntityType)instanceExpression.ResultType.EdmType;
            for (int index = 0; index < entityType.Properties.Count; ++index)
            {
                EdmProperty  property = entityType.Properties[index];
                DbExpression x        = instanceExpression.Arguments[index];
                DbExpression y;
                if (propertyMap.TryGetValue(property, out y))
                {
                    if (!DiscriminatorMap.ExpressionsCompatible(x, y))
                    {
                        return(false);
                    }
                }
                else
                {
                    propertyMap.Add(property, x);
                }
            }
            if (instanceExpression.HasRelatedEntityReferences)
            {
                List <RelProperty> relPropertyList;
                if (!typeToRelPropertyMap.TryGetValue(entityType, out relPropertyList))
                {
                    relPropertyList = new List <RelProperty>();
                    typeToRelPropertyMap[entityType] = relPropertyList;
                }
                foreach (DbRelatedEntityRef relatedEntityReference in instanceExpression.RelatedEntityReferences)
                {
                    RelProperty  key = new RelProperty((RelationshipType)relatedEntityReference.TargetEnd.DeclaringType, relatedEntityReference.SourceEnd, relatedEntityReference.TargetEnd);
                    DbExpression targetEntityReference = relatedEntityReference.TargetEntityReference;
                    DbExpression y;
                    if (relPropertyMap.TryGetValue(key, out y))
                    {
                        if (!DiscriminatorMap.ExpressionsCompatible(targetEntityReference, y))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        relPropertyMap.Add(key, targetEntityReference);
                    }
                    relPropertyList.Add(key);
                }
            }
            return(true);
        }
        /// <summary>
        ///     Given an extent and its corresponding view, invokes the parser to check if the view definition is syntactically correct.
        ///     Iff parsing succeeds: <paramref name="commandTree" /> and <paramref name="discriminatorMap" /> are set to the parse result and method returns true,
        ///     otherwise if parser has thrown a catchable exception, it is returned via <paramref name="parserException" /> parameter,
        ///     otherwise exception is re-thrown.
        /// </summary>
        private static bool TryParseView(
            string eSQL,
            bool isUserSpecified,
            EntitySetBase extent,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config,
            out DbQueryCommandTree commandTree,
            out DiscriminatorMap discriminatorMap,
            out Exception parserException)
        {
            commandTree = null;
            discriminatorMap = null;
            parserException = null;

            // We do not catch any internal exceptions any more
            config.StartSingleWatch(PerfType.ViewParsing);
            try
            {
                // If it is a user specified view, allow all queries. Otherwise parse the view in the restricted mode.
                var compilationMode = ParserOptions.CompilationMode.RestrictedViewGenerationMode;
                if (isUserSpecified)
                {
                    compilationMode = ParserOptions.CompilationMode.UserViewGenerationMode;
                }

                Debug.Assert(!String.IsNullOrEmpty(eSQL), "eSQL query is not specified");
                commandTree = (DbQueryCommandTree)ExternalCalls.CompileView(eSQL, mappingItemCollection, compilationMode);

                // For non user-specified views, perform simplification.
                if (!isUserSpecified)
                {
                    commandTree = ViewSimplifier.SimplifyView(extent, commandTree);
                }

                // See if the view matches the "discriminated" pattern (allows simplification of generated store commands)
                if (extent.BuiltInTypeKind
                    == BuiltInTypeKind.EntitySet)
                {
                    if (DiscriminatorMap.TryCreateDiscriminatorMap((EntitySet)extent, commandTree.Query, out discriminatorMap))
                    {
                        Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created");
                    }
                }
            }
            catch (Exception e)
            {
                // Catching all the exception types since Query parser seems to be throwing veriety of
                // exceptions - EntityException, ArgumentException, ArgumentNullException etc.
                if (e.IsCatchableExceptionType())
                {
                    parserException = e;
                }
                else
                {
                    throw;
                }
            }
            finally
            {
                config.StopSingleWatch(PerfType.ViewParsing);
            }

            Debug.Assert(commandTree != null || parserException != null, "Either commandTree or parserException is expected.");
            // Note: m_commandTree might have been initialized by a previous call to this method, so in consequent calls it might occur that
            // both m_commandTree and parserException are not null - this would mean that the last parse attempt failed, but m_commandTree value is 
            // preserved from the previous call.

            return parserException == null;
        }
        private GeneratedView(
            EntitySetBase extent,
            EdmType type,
            DbQueryCommandTree commandTree,
            string eSQL,
            DiscriminatorMap discriminatorMap,
            StorageMappingItemCollection mappingItemCollection,
            ConfigViewGenerator config)
        {
            // At least one of the commandTree or eSQL must be specified. 
            // Both are specified in the case of user-defined views.
            Debug.Assert(commandTree != null || !String.IsNullOrEmpty(eSQL), "commandTree or eSQL must be specified");

            m_extent = extent;
            m_type = type;
            m_commandTree = commandTree;
            m_eSQL = eSQL;
            m_discriminatorMap = discriminatorMap;
            m_mappingItemCollection = mappingItemCollection;
            m_config = config;

            if (m_config.IsViewTracing)
            {
                var trace = new StringBuilder(1024);
                ToCompactString(trace);
                Helpers.FormatTraceLine("CQL view for {0}", trace.ToString());
            }
        }
        private DbExpression GenerateStructuralTypeResultMappingView(
            DbExpression storeFunctionInvoke, out DiscriminatorMap discriminatorMap)
        {
            Debug.Assert(
                m_structuralTypeMappings != null && m_structuralTypeMappings.Count > 0,
                "m_structuralTypeMappings != null && m_structuralTypeMappings.Count > 0");

            discriminatorMap = null;

            // Process explicit structural type mappings. The mapping is based on the direct call of the store function 
            // wrapped into a projection constructing the mapped structural types.

            var queryExpression = storeFunctionInvoke;

            if (m_structuralTypeMappings.Count == 1)
            {
                var mapping = m_structuralTypeMappings[0];

                var type = mapping.Item1;
                var conditions = mapping.Item2;
                var propertyMappings = mapping.Item3;

                if (conditions.Count > 0)
                {
                    queryExpression = queryExpression.Where((row) => GenerateStructuralTypeConditionsPredicate(conditions, row));
                }

                var binding = queryExpression.BindAs("row");
                var entityTypeMappingView = GenerateStructuralTypeMappingView(type, propertyMappings, binding.Variable);
                if (entityTypeMappingView == null)
                {
                    return null;
                }

                queryExpression = binding.Project(entityTypeMappingView);
            }
            else
            {
                var binding = queryExpression.BindAs("row");

                // Make sure type projection is performed over a closed set where each row is guaranteed to produce a known type.
                // To do this, filter the store function output using the type conditions.
                Debug.Assert(m_structuralTypeMappings.All(m => m.Item2.Count > 0), "In multi-type mapping each type must have conditions.");
                var structuralTypePredicates =
                    m_structuralTypeMappings.Select(m => GenerateStructuralTypeConditionsPredicate(m.Item2, binding.Variable)).ToList();
                queryExpression = binding.Filter(
                    Helpers.BuildBalancedTreeInPlace(
                        structuralTypePredicates.ToArray(), // clone, otherwise BuildBalancedTreeInPlace will change it
                        (prev, next) => prev.Or(next)));
                binding = queryExpression.BindAs("row");

                var structuralTypeMappingViews = new List<DbExpression>(m_structuralTypeMappings.Count);
                foreach (var mapping in m_structuralTypeMappings)
                {
                    var type = mapping.Item1;
                    var propertyMappings = mapping.Item3;

                    var structuralTypeMappingView = GenerateStructuralTypeMappingView(type, propertyMappings, binding.Variable);
                    if (structuralTypeMappingView == null)
                    {
                        continue;
                    }
                    else
                    {
                        structuralTypeMappingViews.Add(structuralTypeMappingView);
                    }
                }
                Debug.Assert(
                    structuralTypeMappingViews.Count == structuralTypePredicates.Count,
                    "structuralTypeMappingViews.Count == structuralTypePredicates.Count");
                if (structuralTypeMappingViews.Count
                    != m_structuralTypeMappings.Count)
                {
                    return null;
                }

                // Because we are projecting over the closed set, we can convert the last WHEN THEN into ELSE.
                DbExpression typeConstructors = DbExpressionBuilder.Case(
                    structuralTypePredicates.Take(m_structuralTypeMappings.Count - 1),
                    structuralTypeMappingViews.Take(m_structuralTypeMappings.Count - 1),
                    structuralTypeMappingViews[m_structuralTypeMappings.Count - 1]);

                queryExpression = binding.Project(typeConstructors);

                if (DiscriminatorMap.TryCreateDiscriminatorMap(FunctionImport.EntitySet, queryExpression, out discriminatorMap))
                {
                    Debug.Assert(discriminatorMap != null, "discriminatorMap == null after it has been created");
                }
            }

            return queryExpression;
        }
        internal DbQueryCommandTree GenerateFunctionView(out DiscriminatorMap discriminatorMap)
        {
            DebugCheck.NotNull(m_mappingItemCollection);

            discriminatorMap = null;

            // Prepare the direct call of the store function as StoreFunction(@EdmFunc_p1, ..., @EdmFunc_pN).
            // Note that function call arguments are command parameters created from the m_edmFunction parameters.
            Debug.Assert(TargetFunction != null, "this.TargetFunction != null");
            DbExpression storeFunctionInvoke = TargetFunction.Invoke(GetParametersForTargetFunctionCall());

            // Generate the query expression producing c-space result from s-space function call(s).
            DbExpression queryExpression;
            if (m_structuralTypeMappings != null)
            {
                queryExpression = GenerateStructuralTypeResultMappingView(storeFunctionInvoke, out discriminatorMap);
                Debug.Assert(
                    queryExpression == null ||
                    TypeSemantics.IsPromotableTo(queryExpression.ResultType, FunctionImport.ReturnParameter.TypeUsage),
                    "TypeSemantics.IsPromotableTo(queryExpression.ResultType, this.FunctionImport.ReturnParameter.TypeUsage)");
            }
            else
            {
                queryExpression = GenerateScalarResultMappingView(storeFunctionInvoke);
                Debug.Assert(
                    queryExpression == null ||
                    TypeSemantics.IsEqual(queryExpression.ResultType, FunctionImport.ReturnParameter.TypeUsage),
                    "TypeSemantics.IsEqual(queryExpression.ResultType, this.FunctionImport.ReturnParameter.TypeUsage)");
            }

            if (queryExpression == null)
            {
                // In case of errors during view generation, return.
                return null;
            }

            // Generate parameterized command, where command parameters are semantically the c-space function parameters.
            return DbQueryCommandTree.FromValidExpression(
                m_mappingItemCollection.Workspace, TargetPerspective.TargetPerspectiveDataSpace, queryExpression);
        }
        internal static bool TryCreateDiscriminatorMap(
            EntitySet entitySet,
            DbExpression queryView,
            out DiscriminatorMap discriminatorMap)
        {
            discriminatorMap = (DiscriminatorMap)null;
            if (queryView.ExpressionKind != DbExpressionKind.Project)
            {
                return(false);
            }
            DbProjectExpression projectExpression = (DbProjectExpression)queryView;

            if (projectExpression.Projection.ExpressionKind != DbExpressionKind.Case)
            {
                return(false);
            }
            DbCaseExpression projection = (DbCaseExpression)projectExpression.Projection;

            if (projectExpression.Projection.ResultType.EdmType.BuiltInTypeKind != BuiltInTypeKind.EntityType || projectExpression.Input.Expression.ExpressionKind != DbExpressionKind.Filter)
            {
                return(false);
            }
            DbFilterExpression expression1         = (DbFilterExpression)projectExpression.Input.Expression;
            HashSet <object>   discriminatorDomain = new HashSet <object>();

            if (!ViewSimplifier.TryMatchDiscriminatorPredicate(expression1, (Action <DbComparisonExpression, object>)((equalsExp, discriminatorValue) => discriminatorDomain.Add(discriminatorValue))))
            {
                return(false);
            }
            List <KeyValuePair <object, EntityType> >    keyValuePairList     = new List <KeyValuePair <object, EntityType> >();
            Dictionary <EdmProperty, DbExpression>       propertyMap          = new Dictionary <EdmProperty, DbExpression>();
            Dictionary <RelProperty, DbExpression>       relPropertyMap       = new Dictionary <RelProperty, DbExpression>();
            Dictionary <EntityType, List <RelProperty> > typeToRelPropertyMap = new Dictionary <EntityType, List <RelProperty> >();
            DbPropertyExpression discriminator = (DbPropertyExpression)null;
            EdmProperty          edmProperty   = (EdmProperty)null;

            for (int index = 0; index < projection.When.Count; ++index)
            {
                DbExpression         expression2  = projection.When[index];
                DbExpression         then         = projection.Then[index];
                string               variableName = projectExpression.Input.VariableName;
                DbPropertyExpression property;
                object               key;
                if (!ViewSimplifier.TryMatchPropertyEqualsValue(expression2, variableName, out property, out key))
                {
                    return(false);
                }
                if (edmProperty == null)
                {
                    edmProperty = (EdmProperty)property.Property;
                }
                else if (edmProperty != property.Property)
                {
                    return(false);
                }
                discriminator = property;
                EntityType entityType;
                if (!DiscriminatorMap.TryMatchEntityTypeConstructor(then, propertyMap, relPropertyMap, typeToRelPropertyMap, out entityType))
                {
                    return(false);
                }
                keyValuePairList.Add(new KeyValuePair <object, EntityType>(key, entityType));
                discriminatorDomain.Remove(key);
            }
            EntityType entityType1;

            if (1 != discriminatorDomain.Count || projection.Else == null || !DiscriminatorMap.TryMatchEntityTypeConstructor(projection.Else, propertyMap, relPropertyMap, typeToRelPropertyMap, out entityType1))
            {
                return(false);
            }
            keyValuePairList.Add(new KeyValuePair <object, EntityType>(discriminatorDomain.Single <object>(), entityType1));
            if (!DiscriminatorMap.CheckForMissingRelProperties(relPropertyMap, typeToRelPropertyMap) || keyValuePairList.Select <KeyValuePair <object, EntityType>, object>((Func <KeyValuePair <object, EntityType>, object>)(map => map.Key)).Distinct <object>((IEqualityComparer <object>)TrailingSpaceComparer.Instance).Count <object>() != keyValuePairList.Count)
            {
                return(false);
            }
            discriminatorMap = new DiscriminatorMap(discriminator, keyValuePairList, propertyMap, relPropertyMap, entitySet);
            return(true);
        }