/// <summary>
        /// Determines the expected shape of store results. We expect a column for every property
        /// of the mapped type (or types) and a column for every discriminator column. We make no
        /// assumptions about the order of columns: the provider is expected to determine appropriate
        /// types by looking at the names of the result columns, not the order of columns, which is
        /// different from the typical handling of row types in the EF.
        /// </summary>
        /// <remarks>
        /// Requires that the given function import mapping refers to a Collection(Entity) or Collection(ComplexType) CSDL
        /// function.
        /// </remarks>
        /// <returns>Row type.</returns>
        internal TypeUsage GetExpectedTargetResultType(MetadataWorkspace workspace, int resultSetIndex)
        {
            FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex);

            // Collect all columns as name-type pairs.
            Dictionary <string, TypeUsage> columns = new Dictionary <string, TypeUsage>();

            // Figure out which entity types we expect to yield from the function.
            IEnumerable <StructuralType> structuralTypes;

            if (0 == resultMapping.NormalizedEntityTypeMappings.Count)
            {
                // No explicit type mappings; just use the type specified in the ReturnType attribute on the function.
                StructuralType structuralType;
                MetadataHelper.TryGetFunctionImportReturnType <StructuralType>(this.FunctionImport, resultSetIndex, out structuralType);
                Debug.Assert(null != structuralType, "this method must be called only for entity/complextype reader function imports");
                structuralTypes = new StructuralType[] { structuralType };
            }
            else
            {
                // Types are explicitly mapped.
                structuralTypes = resultMapping.MappedEntityTypes.Cast <StructuralType>();
            }

            // Gather columns corresponding to all properties.
            foreach (StructuralType structuralType in structuralTypes)
            {
                foreach (EdmProperty property in TypeHelpers.GetAllStructuralMembers(structuralType))
                {
                    // NOTE: if a complex type is encountered, the column map generator will
                    // throw. For now, we just let them through.

                    // We expect to see each property multiple times, so we use indexer rather than
                    // .Add.
                    columns[property.Name] = property.TypeUsage;
                }
            }

            // Gather discriminator columns.
            foreach (string discriminatorColumn in this.GetDiscriminatorColumns(resultSetIndex))
            {
                if (!columns.ContainsKey(discriminatorColumn))
                {
                    //



                    TypeUsage type = TypeUsage.CreateStringTypeUsage(workspace.GetModelPrimitiveType(PrimitiveTypeKind.String), true, false);
                    columns.Add(discriminatorColumn, type);
                }
            }

            // Expected type is a collection of rows
            RowType   rowType = new RowType(columns.Select(c => new EdmProperty(c.Key, c.Value)));
            TypeUsage result  = TypeUsage.Create(new CollectionType(TypeUsage.Create(rowType)));

            return(result);
        }
        internal FunctionImportNormalizedEntityTypeMapping(FunctionImportStructuralTypeMappingKB parent,
                                                           List <FunctionImportEntityTypeMappingCondition> columnConditions, BitArray impliedEntityTypes)
        {
            // validate arguments
            EntityUtil.CheckArgumentNull(parent, "parent");
            EntityUtil.CheckArgumentNull(columnConditions, "discriminatorValues");
            EntityUtil.CheckArgumentNull(impliedEntityTypes, "impliedEntityTypes");

            Debug.Assert(columnConditions.Count == parent.DiscriminatorColumns.Count,
                         "discriminator values must be ordinally aligned with discriminator columns");
            Debug.Assert(impliedEntityTypes.Count == parent.MappedEntityTypes.Count,
                         "implied entity types must be ordinally aligned with mapped entity types");

            this.ColumnConditions             = new OM.ReadOnlyCollection <FunctionImportEntityTypeMappingCondition>(columnConditions.ToList());
            this.ImpliedEntityTypes           = impliedEntityTypes;
            this.ComplementImpliedEntityTypes = (new BitArray(this.ImpliedEntityTypes)).Not();
        }
        internal FunctionImportNormalizedEntityTypeMapping(
            FunctionImportStructuralTypeMappingKB parent,
            List<FunctionImportEntityTypeMappingCondition> columnConditions, BitArray impliedEntityTypes)
        {
            // validate arguments
            //Contract.Requires(parent != null);
            //Contract.Requires(columnConditions != null);
            //Contract.Requires(impliedEntityTypes != null);

            Debug.Assert(
                columnConditions.Count == parent.DiscriminatorColumns.Count,
                "discriminator values must be ordinally aligned with discriminator columns");
            Debug.Assert(
                impliedEntityTypes.Count == parent.MappedEntityTypes.Count,
                "implied entity types must be ordinally aligned with mapped entity types");

            ColumnConditions = new ReadOnlyCollection<FunctionImportEntityTypeMappingCondition>(columnConditions.ToList());
            ImpliedEntityTypes = impliedEntityTypes;
            ComplementImpliedEntityTypes = (new BitArray(ImpliedEntityTypes)).Not();
        }
        /// <summary>
        /// Gets the disctriminator columns resultSetIndexth result set, or an empty array if the index is not in range
        /// </summary>
        internal IList <string> GetDiscriminatorColumns(int resultSetIndex)
        {
            FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex);

            return(resultMapping.DiscriminatorColumns);
        }
        /// <summary>
        /// Given discriminator values (ordinally aligned with DiscriminatorColumns), determines
        /// the entity type to return. Throws a CommandExecutionException if the type is ambiguous.
        /// </summary>
        internal EntityType Discriminate(object[] discriminatorValues, int resultSetIndex)
        {
            FunctionImportStructuralTypeMappingKB resultMapping = this.GetResultMapping(resultSetIndex);

            Debug.Assert(resultMapping != null);

            // initialize matching types bit map
            BitArray typeCandidates = new BitArray(resultMapping.MappedEntityTypes.Count, true);

            foreach (var typeMapping in resultMapping.NormalizedEntityTypeMappings)
            {
                // check if this type mapping is matched
                bool matches          = true;
                var  columnConditions = typeMapping.ColumnConditions;
                for (int i = 0; i < columnConditions.Count; i++)
                {
                    if (null != columnConditions[i] && // this discriminator doesn't matter for the given condition
                        !columnConditions[i].ColumnValueMatchesCondition(discriminatorValues[i]))
                    {
                        matches = false;
                        break;
                    }
                }

                if (matches)
                {
                    // if the type condition is met, narrow the set of type candidates
                    typeCandidates = typeCandidates.And(typeMapping.ImpliedEntityTypes);
                }
                else
                {
                    // if the type condition fails, all implied types are eliminated
                    // (the type mapping fragment is a co-implication, so a type is no longer
                    // a candidate if any condition referring to it is false)
                    typeCandidates = typeCandidates.And(typeMapping.ComplementImpliedEntityTypes);
                }
            }

            // find matching type condition
            EntityType entityType = null;

            for (int i = 0; i < typeCandidates.Length; i++)
            {
                if (typeCandidates[i])
                {
                    if (null != entityType)
                    {
                        throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType);
                    }
                    entityType = resultMapping.MappedEntityTypes[i];
                }
            }

            // if there is no match, raise an exception
            if (null == entityType)
            {
                throw EntityUtil.CommandExecution(System.Data.Entity.Strings.ADP_InvalidDataReaderUnableToDetermineType);
            }

            return(entityType);
        }