/// <summary>
        /// Copies the DiscriminatedEntityIdentity
        /// </summary>
        /// <param name="entityIdentity"></param>
        /// <param name="replacementVarMap"></param>
        /// <returns></returns>
        protected override EntityIdentity VisitEntityIdentity(DiscriminatedEntityIdentity entityIdentity, VarMap replacementVarMap)
        {
            SimpleColumnMap newEntitySetCol = (SimpleColumnMap)entityIdentity.EntitySetColumnMap.Accept(this, replacementVarMap);

            SimpleColumnMap[] newKeys = VisitList(entityIdentity.Keys, replacementVarMap);
            return(new DiscriminatedEntityIdentity(newEntitySetCol, entityIdentity.EntitySetMap, newKeys));
        }
Exemple #2
0
        private md.EntitySet[] m_entitySetMap;     // optional dictionary that maps values to entitysets

        /// <summary>
        /// Simple constructor
        /// </summary>
        /// <param name="entitySetColumn">column map representing the entityset</param>
        /// <param name="entitySetMap">Map from value -> the appropriate entityset</param>
        /// <param name="keyColumns">list of key columns</param>
        internal DiscriminatedEntityIdentity(SimpleColumnMap entitySetColumn, md.EntitySet[] entitySetMap,
                                             SimpleColumnMap[] keyColumns)
            : base(keyColumns)
        {
            Debug.Assert(entitySetColumn != null, "Must specify a column map to identify the entity set");
            Debug.Assert(entitySetMap != null, "Must specify a dictionary to look up entitysets");
            m_entitySetColumn = entitySetColumn;
            m_entitySetMap    = entitySetMap;
        }
        /// <summary>
        /// DiscriminatedCollectionColumnMap
        /// </summary>
        /// <param name="columnMap"></param>
        /// <param name="replacementVarMap"></param>
        /// <returns></returns>
        internal override ColumnMap Visit(DiscriminatedCollectionColumnMap columnMap, VarMap replacementVarMap)
        {
            ColumnMap       newElementColumnMap = columnMap.Element.Accept(this, replacementVarMap);
            SimpleColumnMap newDiscriminator    = (SimpleColumnMap)columnMap.Discriminator.Accept(this, replacementVarMap);

            SimpleColumnMap[] newKeys        = VisitList(columnMap.Keys, replacementVarMap);
            SimpleColumnMap[] newForeignKeys = VisitList(columnMap.ForeignKeys, replacementVarMap);
            return(new DiscriminatedCollectionColumnMap(columnMap.Type, columnMap.Name, newElementColumnMap, newKeys, newForeignKeys, newDiscriminator, columnMap.DiscriminatorValue));
        }
        private readonly EntitySet[] m_entitySetMap; // optional dictionary that maps values to entitysets

        /// <summary>
        /// Simple constructor
        /// </summary>
        /// <param name="entitySetColumn">column map representing the entityset</param>
        /// <param name="entitySetMap">Map from value -> the appropriate entityset</param>
        /// <param name="keyColumns">list of key columns</param>
        internal DiscriminatedEntityIdentity(
            SimpleColumnMap entitySetColumn, EntitySet[] entitySetMap,
            SimpleColumnMap[] keyColumns)
            : base(keyColumns)
        {
            Debug.Assert(entitySetColumn != null, "Must specify a column map to identify the entity set");
            Debug.Assert(entitySetMap != null, "Must specify a dictionary to look up entitysets");
            m_entitySetColumn = entitySetColumn;
            m_entitySetMap = entitySetMap;
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="type">datatype of column</param>
        /// <param name="name">column name</param>
        /// <param name="elementMap">column map for collection element</param>
        /// <param name="keys">List of keys</param>
        /// <param name="foreignKeys">List of foreign keys</param>
        internal CollectionColumnMap(
            TypeUsage type, string name, ColumnMap elementMap, SimpleColumnMap[] keys, SimpleColumnMap[] foreignKeys)
            : base(type, name)
        {
            Debug.Assert(elementMap != null, "Must specify column map for element");

            m_element = elementMap;
            m_keys = keys ?? new SimpleColumnMap[0];
            m_foreignKeys = foreignKeys ?? new SimpleColumnMap[0];
        }
        /// <summary>
        /// RecordColumnMap
        /// </summary>
        /// <param name="columnMap"></param>
        /// <param name="replacementVarMap"></param>
        /// <returns></returns>
        internal override ColumnMap Visit(RecordColumnMap columnMap, VarMap replacementVarMap)
        {
            SimpleColumnMap newNullability = columnMap.NullSentinel;

            if (null != newNullability)
            {
                newNullability = (SimpleColumnMap)newNullability.Accept(this, replacementVarMap);
            }
            ColumnMap[] fieldList = VisitList(columnMap.Properties, replacementVarMap);
            return(new RecordColumnMap(columnMap.Type, columnMap.Name, fieldList, newNullability));
        }
Exemple #7
0
 /// <summary>
 /// Internal constructor
 /// </summary>
 /// <param name="type">datatype of the column</param>
 /// <param name="name">column name</param>
 /// <param name="typeDiscriminator">column map for type discriminator column</param>
 /// <param name="baseTypeColumns">base list of fields common to all types</param>
 /// <param name="typeChoices">map from type discriminator value->columnMap</param>
 internal SimplePolymorphicColumnMap(md.TypeUsage type,
                                     string name,
                                     ColumnMap[] baseTypeColumns,
                                     SimpleColumnMap typeDiscriminator,
                                     Dictionary <object, TypedColumnMap> typeChoices)
     : base(type, name, baseTypeColumns)
 {
     Debug.Assert(typeDiscriminator != null, "Must specify a type discriminator column");
     Debug.Assert(typeChoices != null, "No type choices for polymorphic column");
     m_typedColumnMap    = typeChoices;
     m_typeDiscriminator = typeDiscriminator;
 }
Exemple #8
0
 /// <summary>
 /// Internal constructor
 /// </summary>
 /// <param name="type">Column datatype</param>
 /// <param name="name">column name</param>
 /// <param name="elementMap">column map for collection element</param>
 /// <param name="keys">Keys for the collection</param>
 /// <param name="foreignKeys">Foreign keys for the collection</param>
 /// <param name="discriminator">Discriminator column map</param>
 /// <param name="discriminatorValue">Discriminator value</param>
 internal DiscriminatedCollectionColumnMap(md.TypeUsage type, string name,
                                           ColumnMap elementMap,
                                           SimpleColumnMap[] keys,
                                           SimpleColumnMap[] foreignKeys,
                                           SimpleColumnMap discriminator,
                                           object discriminatorValue)
     : base(type, name, elementMap, keys, foreignKeys)
 {
     Debug.Assert(discriminator != null, "Must specify a column map for the collection discriminator");
     Debug.Assert(discriminatorValue != null, "Must specify a discriminator value");
     m_discriminator      = discriminator;
     m_discriminatorValue = discriminatorValue;
 }
        /// <summary>
        /// SimplePolymorphicColumnMap
        /// </summary>
        /// <param name="columnMap"></param>
        /// <param name="replacementVarMap"></param>
        /// <returns></returns>
        internal override ColumnMap Visit(SimplePolymorphicColumnMap columnMap, VarMap replacementVarMap)
        {
            SimpleColumnMap newDiscriminator = (SimpleColumnMap)columnMap.TypeDiscriminator.Accept(this, replacementVarMap);

            Dictionary <object, TypedColumnMap> newTypeChoices = new Dictionary <object, TypedColumnMap>(columnMap.TypeChoices.Comparer);

            foreach (KeyValuePair <object, TypedColumnMap> kv in columnMap.TypeChoices)
            {
                TypedColumnMap newMap = (TypedColumnMap)kv.Value.Accept(this, replacementVarMap);
                newTypeChoices[kv.Key] = newMap;
            }
            ColumnMap[] newBaseFieldList = VisitList(columnMap.Properties, replacementVarMap);
            return(new SimplePolymorphicColumnMap(columnMap.Type, columnMap.Name, newBaseFieldList, newDiscriminator, newTypeChoices));
        }
Exemple #10
0
        /// <summary>
        /// Build the entityColumnMap from a store datareader, a type and an entitySet and
        /// a list ofproperties.
        /// </summary>
        /// <param name="storeDataReader"></param>
        /// <param name="edmType"></param>
        /// <param name="entitySet"></param>
        /// <param name="propertyColumnMaps"></param>
        /// <returns></returns>
        private static EntityColumnMap CreateEntityTypeElementColumnMap(
            DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet,
            ColumnMap[] propertyColumnMaps, Dictionary <string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
        {
            EntityType entityType = (EntityType)edmType;

            // The tricky part here is
            // that the KeyColumns list must point at the same ColumnMap(s) that
            // the properties list points to, so we build a quick array of
            // ColumnMap(s) that are indexed by their ordinal; then we can walk
            // the list of keyMembers, and find the ordinal in the reader, and
            // pick the same ColumnMap for it.

            // Build the ordinal -> ColumnMap index
            ColumnMap[] ordinalToColumnMap = new ColumnMap[storeDataReader.FieldCount];

            foreach (ColumnMap propertyColumnMap in propertyColumnMaps)
            {
                int ordinal = ((ScalarColumnMap)propertyColumnMap).ColumnPos;
                ordinalToColumnMap[ordinal] = propertyColumnMap;
            }

            // Now build the list of KeyColumns;
            IList <EdmMember> keyMembers = entityType.KeyMembers;

            SimpleColumnMap[] keyColumns = new SimpleColumnMap[keyMembers.Count];

            int keyMemberIndex = 0;

            foreach (EdmMember keyMember in keyMembers)
            {
                int keyOrdinal = GetMemberOrdinalFromReader(storeDataReader, keyMember, edmType, renameList);

                Debug.Assert(keyOrdinal >= 0, "keyMember for entity is not found by name in the data reader?");

                ColumnMap keyColumnMap = ordinalToColumnMap[keyOrdinal];

                Debug.Assert(null != keyColumnMap, "keyMember for entity isn't in properties collection for the entity?");
                keyColumns[keyMemberIndex] = (SimpleColumnMap)keyColumnMap;
                keyMemberIndex++;
            }

            SimpleEntityIdentity entityIdentity = new SimpleEntityIdentity(entitySet, keyColumns);

            EntityColumnMap result = new EntityColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, entityIdentity);

            return(result);
        }
Exemple #11
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="type">column Datatype</param>
 /// <param name="name">column name</param>
 /// <param name="properties">list of properties</param>
 internal ComplexTypeColumnMap(md.TypeUsage type, string name, ColumnMap[] properties, SimpleColumnMap nullSentinel)
     : base(type, name, properties)
 {
     m_nullSentinel = nullSentinel;
 }
        /// <summary>
        /// convert MultiStreamNestOp to SingleStreamNestOp
        /// </summary>
        /// <remarks>
        /// A MultiStreamNestOp is typically of the form M(D, N1, N2, ..., Nk)
        /// where D is the driver stream, and N1, N2 etc. represent the collections.
        ///
        /// In general, this can be converted into a SingleStreamNestOp over:
        ///
        ///    (D+ outerApply N1) AugmentedUnionAll (D+ outerApply N2) ...
        ///
        /// Where:
        ///
        ///     D+ is D with an extra discriminator column that helps to identify
        ///     the specific collection.
        ///
        ///     AugmentedUnionAll is simply a unionAll where each branch of the
        ///     unionAll is augmented with nulls for the corresponding columns
        ///     of other tables in the branch
        ///
        /// The simple case where there is only a single nested collection is easier
        /// to address, and can be represented by:
        ///
        ///     MultiStreamNest(D, N1) => SingleStreamNest(OuterApply(D, N1))
        ///
        /// The more complex case, where there is more than one nested column, requires
        /// quite a bit more work:
        ///
        ///     MultiStreamNest(D, X, Y,...) => SingleStreamNest(UnionAll(Project{"1", D1...Dn, X1...Xn, nY1...nYn}(OuterApply(D, X)), Project{"2", D1...Dn, nX1...nXn, Y1...Yn}(OuterApply(D, Y)), ...))
        ///
        /// Where:
        ///      D           is the driving collection
        ///      D1...Dn     are the columns from the driving collection
        ///      X           is the first nested collection
        ///      X1...Xn     are the columns from the first nested collection
        ///      nX1...nXn   are null values for all columns from the first nested collection
        ///      Y           is the second nested collection
        ///      Y1...Yn     are the columns from the second nested collection
        ///      nY1...nYn   are null values for all columns from the second nested collection
        /// </remarks>
        /// <param name="nestNode"></param>
        /// <param name="varRefReplacementMap"></param>
        /// <param name="flattenedOutputVarList"></param>
        /// <param name="parentKeyColumnMaps"></param>
        /// <returns></returns>
        private Node ConvertToSingleStreamNest(
            Node nestNode, Dictionary<Var, ColumnMap> varRefReplacementMap, VarList flattenedOutputVarList,
            out SimpleColumnMap[] parentKeyColumnMaps)
        {
#if DEBUG
            var input = Dump.ToXml(nestNode);
#endif
            //DEBUG
            var nestOp = (MultiStreamNestOp)nestNode.Op;

            // We can't convert this node to a SingleStreamNest until all it's MultiStreamNest 
            // inputs are converted, so do that first.
            for (var i = 1; i < nestNode.Children.Count; i++)
            {
                var chi = nestNode.Children[i];

                if (chi.Op.OpType
                    == OpType.MultiStreamNest)
                {
                    var chiCi = nestOp.CollectionInfo[i - 1];

                    var childFlattenedOutputVars = Command.CreateVarList();
                    SimpleColumnMap[] childKeyColumnMaps;

                    nestNode.Children[i] = ConvertToSingleStreamNest(
                        chi, varRefReplacementMap, childFlattenedOutputVars, out childKeyColumnMaps);

                    // Now this may seem odd here, and it may look like we should have done this
                    // inside the recursive ConvertToSingleStreamNest call above, but that call
                    // doesn't have access to the CollectionInfo for it's parent, which is what
                    // we need to manipulate before we enter the loop below where we try and fold
                    // THIS nestOp nodes into a singleStreamNestOp.
                    var childColumnMap = ColumnMapTranslator.Translate(chiCi.ColumnMap, varRefReplacementMap);

                    var childKeys = Command.CreateVarVec(((SingleStreamNestOp)nestNode.Children[i].Op).Keys);

                    nestOp.CollectionInfo[i - 1] = Command.CreateCollectionInfo(
                        chiCi.CollectionVar,
                        childColumnMap,
                        childFlattenedOutputVars,
                        childKeys,
                        chiCi.SortKeys,
                        null /*discriminatorValue*/
                        );
                }
            }

            // Make sure that the driving node has keys defined. Otherwise we're in
            // trouble; we must be able to infer keys from the driving node.
            var drivingNode = nestNode.Child0;
            var drivingNodeKeys = Command.PullupKeys(drivingNode);
            if (drivingNodeKeys.NoKeys)
            {
                // ALMINEEV: In this case we used to wrap drivingNode into a projection that would also project Edm.NewGuid() thus giving us a synthetic key.
                // This solution did not work however due to a bug in SQL Server that allowed pulling non-deterministic functions above joins and applies, thus 
                // producing incorrect results. SQL Server bug was filed in "sqlbuvsts01\Sql Server" database as #725272.
                // The only known path how we can get a keyless drivingNode is if 
                //    - drivingNode is over a TVF call
                //    - TVF is declared as Collection(Row) is SSDL (the only form of TVF definitions at the moment)
                //    - TVF is not mapped to entities
                //      Note that if TVF is mapped to entities via function import mapping, and the user query is actually the call of the 
                //      function import, we infer keys for the TVF from the c-space entity keys and their mappings.
                throw new NotSupportedException(Strings.ADP_KeysRequiredForNesting);
            }

            // Get a deterministic ordering of Vars from this node.
            // NOTE: we're using the drivingNode's definitions, which is a VarVec so it
            //       won't match the order of the input's columns, but the key thing is 
            //       that we use the same order for all nested children, so it's OK.
            var drivingNodeInfo = Command.GetExtendedNodeInfo(drivingNode);
            var drivingNodeVarVec = drivingNodeInfo.Definitions;
            var drivingNodeVars = Command.CreateVarList(drivingNodeVarVec);

            // Normalize all collection inputs to the nestOp. Specifically, remove any
            // SortOps (adding the sort keys to the postfix sortkey list). Additionally,
            // add a discriminatorVar to each collection child
            VarList discriminatorVarList;
            List<List<SortKey>> postfixSortKeyList;
            NormalizeNestOpInputs(nestOp, nestNode, out discriminatorVarList, out postfixSortKeyList);

            // Now build up the union-all subquery
            List<Dictionary<Var, Var>> varMapList;
            Var outputDiscriminatorVar;
            var unionAllNode = BuildUnionAllSubqueryForNestOp(
                nestOp, nestNode, drivingNodeVars, discriminatorVarList, out outputDiscriminatorVar, out varMapList);
            var drivingNodeVarMap = varMapList[0];

            // OK.  We've finally created the UnionAll over each of the project/outerApply
            // combinations.  We know that the output columns will be:
            //
            //      Discriminator, DrivingColumns, Collection1Columns, Collection2Columns, ...
            //
            // Now, rebuild the columnMaps, since all of the columns in the original column
            // maps are now referencing newer variables.  To do that, we'll walk the list of
            // outputs from the unionAll, and construct new VarRefColumnMaps for each one,
            // and adding it to a ColumnMapPatcher, which we'll use to actually fix everything
            // up.
            //
            // While we're at it, we'll build a new list of top-level output columns, which
            // should include only the Discriminator, the columns from the driving collection,
            // and and one column for each of the nested collections.

            // Start building the flattenedOutputVarList that the top level PhysicalProjectOp
            // is to output.
            flattenedOutputVarList.AddRange(RemapVars(drivingNodeVars, drivingNodeVarMap));

            var flattenedOutputVarVec = Command.CreateVarVec(flattenedOutputVarList);
            var nestOpOutputs = Command.CreateVarVec(flattenedOutputVarVec);

            // Add any adjustments to the driving nodes vars to the column map patcher
            foreach (var kv in drivingNodeVarMap)
            {
                if (kv.Key
                    != kv.Value)
                {
                    varRefReplacementMap[kv.Key] = new VarRefColumnMap(kv.Value);
                }
            }

            RemapSortKeys(nestOp.PrefixSortKeys, drivingNodeVarMap);

            var newPostfixSortKeys = new List<SortKey>();
            var newCollectionInfoList = new List<CollectionInfo>();

            // Build the discriminator column map, and ensure it's in the outputs
            var discriminatorColumnMap = new VarRefColumnMap(outputDiscriminatorVar);
            nestOpOutputs.Set(outputDiscriminatorVar);

            if (!flattenedOutputVarVec.IsSet(outputDiscriminatorVar))
            {
                flattenedOutputVarList.Add(outputDiscriminatorVar);
                flattenedOutputVarVec.Set(outputDiscriminatorVar);
            }

            // Build the key column maps, and ensure they're in the outputs as well.
            var parentKeys = RemapVarVec(drivingNodeKeys.KeyVars, drivingNodeVarMap);
            parentKeyColumnMaps = new SimpleColumnMap[parentKeys.Count];

            var index = 0;
            foreach (var keyVar in parentKeys)
            {
                parentKeyColumnMaps[index] = new VarRefColumnMap(keyVar);
                index++;

                if (!flattenedOutputVarVec.IsSet(keyVar))
                {
                    flattenedOutputVarList.Add(keyVar);
                    flattenedOutputVarVec.Set(keyVar);
                }
            }

            // Now that we've handled the driving node, deal with each of the 
            // nested inputs, in sequence.
            for (var i = 1; i < nestNode.Children.Count; i++)
            {
                var ci = nestOp.CollectionInfo[i - 1];
                var postfixSortKeys = postfixSortKeyList[i];

                RemapSortKeys(postfixSortKeys, varMapList[i]);
                newPostfixSortKeys.AddRange(postfixSortKeys);

                var newColumnMap = ColumnMapTranslator.Translate(ci.ColumnMap, varMapList[i]);
                var newFlattenedElementVars = RemapVarList(ci.FlattenedElementVars, varMapList[i]);
                var newCollectionKeys = RemapVarVec(ci.Keys, varMapList[i]);

                RemapSortKeys(ci.SortKeys, varMapList[i]);

                var newCollectionInfo = Command.CreateCollectionInfo(
                    ci.CollectionVar,
                    newColumnMap,
                    newFlattenedElementVars,
                    newCollectionKeys,
                    ci.SortKeys,
                    i);
                newCollectionInfoList.Add(newCollectionInfo);

                // For a collection Var, we add the flattened elementVars for the
                // collection in place of the collection Var itself, and we create
                // a new column map to represent all the stuff we've done.

                foreach (var v in newFlattenedElementVars)
                {
                    if (!flattenedOutputVarVec.IsSet(v))
                    {
                        flattenedOutputVarList.Add(v);
                        flattenedOutputVarVec.Set(v);
                    }
                }

                nestOpOutputs.Set(ci.CollectionVar);

                var keyColumnMapIndex = 0;
                var keyColumnMaps = new SimpleColumnMap[newCollectionInfo.Keys.Count];
                foreach (var keyVar in newCollectionInfo.Keys)
                {
                    keyColumnMaps[keyColumnMapIndex] = new VarRefColumnMap(keyVar);
                    keyColumnMapIndex++;
                }

                var collectionColumnMap = new DiscriminatedCollectionColumnMap(
                    TypeUtils.CreateCollectionType(newCollectionInfo.ColumnMap.Type),
                    newCollectionInfo.ColumnMap.Name,
                    newCollectionInfo.ColumnMap,
                    keyColumnMaps,
                    parentKeyColumnMaps,
                    discriminatorColumnMap,
                    newCollectionInfo.DiscriminatorValue
                    );
                varRefReplacementMap[ci.CollectionVar] = collectionColumnMap;
            }

            // Finally, build up the SingleStreamNest Node
            var newSsnOp = Command.CreateSingleStreamNestOp(
                parentKeys,
                nestOp.PrefixSortKeys,
                newPostfixSortKeys,
                nestOpOutputs,
                newCollectionInfoList,
                outputDiscriminatorVar);
            var newNestNode = Command.CreateNode(newSsnOp, unionAllNode);

#if DEBUG
            var size = input.Length; // GC.KeepAlive makes FxCop Grumpy.
            var output = Dump.ToXml(newNestNode);
#endif
            //DEBUG

            return newNestNode;
        }
        private readonly EntitySet m_entitySet; // the entity set

        /// <summary>
        /// Basic constructor.
        /// Note: the entitySet may be null - in which case, we are referring to
        /// a transient entity
        /// </summary>
        /// <param name="entitySet">The entityset</param>
        /// <param name="keyColumns">key columns of the entity</param>
        internal SimpleEntityIdentity(EntitySet entitySet, SimpleColumnMap[] keyColumns)
            : base(keyColumns)
        {
            // the entityset may be null
            m_entitySet = entitySet;
        }
        /// <summary>
        /// Build the entityColumnMap from a store datareader, a type and an entitySet and 
        /// a list ofproperties.
        /// </summary>
        /// <param name="storeDataReader"></param>
        /// <param name="edmType"></param>
        /// <param name="entitySet"></param>
        /// <param name="propertyColumnMaps"></param>
        /// <returns></returns>
        private static EntityColumnMap CreateEntityTypeElementColumnMap(
            DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet,
            ColumnMap[] propertyColumnMaps, Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
        {
            EntityType entityType = (EntityType)edmType;

            // The tricky part here is
            // that the KeyColumns list must point at the same ColumnMap(s) that 
            // the properties list points to, so we build a quick array of 
            // ColumnMap(s) that are indexed by their ordinal; then we can walk
            // the list of keyMembers, and find the ordinal in the reader, and 
            // pick the same ColumnMap for it.

            // Build the ordinal -> ColumnMap index
            ColumnMap[] ordinalToColumnMap = new ColumnMap[storeDataReader.FieldCount];

            foreach (ColumnMap propertyColumnMap in propertyColumnMaps)
            {
                int ordinal = ((ScalarColumnMap)propertyColumnMap).ColumnPos;
                ordinalToColumnMap[ordinal] = propertyColumnMap;
            }

            // Now build the list of KeyColumns;
            IList<EdmMember> keyMembers = entityType.KeyMembers;
            SimpleColumnMap[] keyColumns = new SimpleColumnMap[keyMembers.Count];

            int keyMemberIndex = 0;
            foreach (EdmMember keyMember in keyMembers)
            {
                int keyOrdinal = GetMemberOrdinalFromReader(storeDataReader, keyMember, edmType, renameList);

                Debug.Assert(keyOrdinal >= 0, "keyMember for entity is not found by name in the data reader?");

                ColumnMap keyColumnMap = ordinalToColumnMap[keyOrdinal];

                Debug.Assert(null != keyColumnMap, "keyMember for entity isn't in properties collection for the entity?");
                keyColumns[keyMemberIndex] = (SimpleColumnMap)keyColumnMap;
                keyMemberIndex++;
            }

            SimpleEntityIdentity entityIdentity = new SimpleEntityIdentity(entitySet, keyColumns);

            EntityColumnMap result = new EntityColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, entityIdentity);
            return result;
        }
        /// <summary>
        /// Create a column map for a ref type
        /// </summary>
        /// <param name="typeInfo">Type information for the ref type</param>
        /// <param name="name">Name of the column</param>
        /// <returns>Column map for the ref type</returns>
        private RefColumnMap CreateRefColumnMap(TypeInfo typeInfo, string name)
        {
            SimpleColumnMap entitySetIdColumnMap = null;
            if (typeInfo.HasEntitySetIdProperty)
            {
                entitySetIdColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.EntitySetIdProperty), c_EntitySetIdColumnName);
            }

            // get the target entity type, 
            md.EntityType entityType = (md.EntityType)(TypeHelpers.GetEdmType<md.RefType>(typeInfo.Type).ElementType);

            // Iterate through the list of "key" properties
            SimpleColumnMap[] keyColList = new SimpleColumnMap[entityType.KeyMembers.Count];
            for (int i = 0; i < keyColList.Length; ++i)
            {
                md.EdmMember property = entityType.KeyMembers[i];
                keyColList[i] = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
            }

            // Create the entity identity
            EntityIdentity identity = CreateEntityIdentity(entityType, entitySetIdColumnMap, keyColList);

            RefColumnMap result = new RefColumnMap(typeInfo.Type, name, identity);
            return result;
        }
 /// <summary>
 /// Build out an EntityIdentity structure - for use by EntityColumnMap and RefColumnMap
 /// </summary>
 /// <param name="entityType">the entity type in question</param>
 /// <param name="entitySetIdColumnMap">column map for the entitysetid column</param>
 /// <param name="keyColumnMaps">column maps for the keys</param>
 /// <returns></returns>
 private EntityIdentity CreateEntityIdentity(md.EntityType entityType,
     SimpleColumnMap entitySetIdColumnMap,
     SimpleColumnMap[] keyColumnMaps)
 {
     //
     // If we have an entitysetid (and therefore, a column map for the entitysetid), 
     // then use a discriminated entity identity; otherwise, we use a simpleentityidentity
     // instead
     //
     if (entitySetIdColumnMap != null)
     {
         return new DiscriminatedEntityIdentity(entitySetIdColumnMap, m_typeInfo.EntitySetIdToEntitySetMap, keyColumnMaps);
     }
     else
     {
         md.EntitySet entitySet = m_typeInfo.GetEntitySet(entityType);
         PlanCompiler.Assert(entitySet != null, "Expected non-null entityset when no entitysetid is required. Entity type = " + entityType);
         return new SimpleEntityIdentity(entitySet, keyColumnMaps);
     }
 }
        private readonly SimpleColumnMap[] m_keys; // list of keys

        /// <summary>
        /// Simple constructor - gets a list of key columns
        /// </summary>
        /// <param name="keyColumns"></param>
        internal EntityIdentity(SimpleColumnMap[] keyColumns)
        {
            Debug.Assert(keyColumns != null, "Must specify column maps for key columns");
            m_keys = keyColumns;
        }