columnmapfactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Query / InternalTrees / columnmapfactory.cs / 1305376 / columnmapfactory.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// @owner  [....] 
// @backupOwner [....]
//----------------------------------------------------------------------------- 
 
using System.Data.Common;
using System.Data.Mapping; 
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data.Common.Utils; 
using System.Linq;
using System.Reflection; 
using System.Linq.Expressions; 
using System.Data.Objects.ELinq;
using System.Data.Entity; 

namespace System.Data.Query.InternalTrees
{
    ///  
    /// Factory methods for prescriptive column map patterns (includes default
    /// column maps for -- soon to be -- public materializer services and function 
    /// mappings). 
    /// 
    internal static class ColumnMapFactory 
    {
        /// 
        /// Creates a column map for the given reader and function mapping.
        ///  
        internal static CollectionColumnMap CreateFunctionImportStructuralTypeColumnMap(DbDataReader storeDataReader, FunctionImportMapping mapping, EntitySet entitySet, StructuralType baseStructuralType)
        { 
            if (mapping.NormalizedEntityTypeMappings.Count == 0) // no explicit mapping; use default non-polymorphic reader 
            {
                // if there is no mapping, create default mapping to root entity type or complex type 
                Debug.Assert(!baseStructuralType.Abstract, "mapping loader must verify abstract types have explicit mapping");

                return CreateColumnMapFromReaderAndType(storeDataReader, baseStructuralType, entitySet, mapping.ReturnTypeColumnsRenameMapping);
            } 

            // the section below deals with the polymorphic entity type mapping for return type 
            EntityType baseEntityType = baseStructuralType as EntityType; 
            Debug.Assert(null != baseEntityType, "We should have entity type here");
 
            // Generate column maps for all discriminators
            ScalarColumnMap[] discriminatorColumns = CreateDiscriminatorColumnMaps(storeDataReader, mapping);

            // Generate default maps for all mapped entity types 
            var mappedEntityTypes = new HashSet(mapping.MappedEntityTypes);
            mappedEntityTypes.Add(baseEntityType); // make sure the base type is represented 
            Dictionary typeChoices = new Dictionary(mappedEntityTypes.Count); 
            ColumnMap[] baseTypeColumnMaps = null;
            foreach (EntityType entityType in mappedEntityTypes) 
            {

                ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, entityType, mapping.ReturnTypeColumnsRenameMapping);
                EntityColumnMap entityColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, entityType, entitySet, propertyColumnMaps, mapping.ReturnTypeColumnsRenameMapping); 
                if (!entityType.Abstract)
                { 
                    typeChoices.Add(entityType, entityColumnMap); 
                }
                if (entityType == baseStructuralType) 
                {
                    baseTypeColumnMaps = propertyColumnMaps;
                }
            } 

            // NOTE: We don't have a null sentinel here, because the stored proc won't 
            //       return one anyway; we'll just presume the data's always there. 
            MultipleDiscriminatorPolymorphicColumnMap polymorphicMap = new MultipleDiscriminatorPolymorphicColumnMap(TypeUsage.Create(baseStructuralType), baseStructuralType.Name, baseTypeColumnMaps, discriminatorColumns, typeChoices, mapping.Discriminate);
            CollectionColumnMap collection = new SimpleCollectionColumnMap(baseStructuralType.GetCollectionType().TypeUsage, baseStructuralType.Name, polymorphicMap, null, null); 
            return collection;
        }

        ///  
        /// Build the collectionColumnMap from a store datareader, a type and an entitySet.
        ///  
        ///  
        /// 
        ///  
        /// 
        internal static CollectionColumnMap CreateColumnMapFromReaderAndType(DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet, Dictionary renameList)
        {
            Debug.Assert(Helper.IsEntityType(edmType) || null == entitySet, "The specified non-null EntitySet is incompatible with the EDM type specified."); 

            // Next, build the ColumnMap directly from the edmType and entitySet provided. 
            ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, edmType, renameList); 
            ColumnMap elementColumnMap = null;
 
            // NOTE: We don't have a null sentinel here, because the stored proc won't
            //       return one anyway; we'll just presume the data's always there.
            if (Helper.IsRowType(edmType))
            { 
                elementColumnMap = new RecordColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null);
            } 
            else if (Helper.IsComplexType(edmType)) 
            {
                elementColumnMap = new ComplexTypeColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null); 
            }
            else if (Helper.IsPrimitiveType(edmType))
            {
                if (storeDataReader.FieldCount != 1) 
                {
                    throw EntityUtil.CommandExecutionDataReaderFieldCountForPrimitiveType(); 
                } 
                elementColumnMap = new ScalarColumnMap(TypeUsage.Create(edmType), edmType.Name, 0, 0);
            } 
            else if (Helper.IsEntityType(edmType))
            {
                elementColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, edmType, entitySet, propertyColumnMaps, null/*renameList*/);
            } 
            else
            { 
                Debug.Assert(false, "unexpected edmType?"); 
            }
            CollectionColumnMap collection = new SimpleCollectionColumnMap(edmType.GetCollectionType().TypeUsage, edmType.Name, elementColumnMap, null, null); 
            return collection;
        }

        ///  
        /// Requires: a public type with a public, default constructor. Returns a column map initializing the type
        /// and all properties of the type with a public setter taking a primitive type and having a corresponding 
        /// column in the reader. 
        /// 
        internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(DbDataReader reader, Type type, MetadataWorkspace workspace) 
        {
            Debug.Assert(null != reader);
            Debug.Assert(null != type);
            Debug.Assert(null != workspace); 

            // we require a default constructor 
            ConstructorInfo constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, 
                null, Type.EmptyTypes, null);
            if (type.IsAbstract || (null == constructor && !type.IsValueType)) 
            {
                throw EntityUtil.InvalidOperation(
                    Strings.ObjectContext_InvalidTypeForStoreQuery(type));
            } 

            // build a LINQ expression used by result assembly to create results 
            var memberInfo = new List>(); 
            foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            { 
                Type propType = prop.PropertyType;
                EdmType modelType;
                int ordinal;
                if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) && 
                    MetadataHelper.TryDetermineCSpaceModelType(propType, workspace, out modelType) &&
                    modelType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType && 
                    prop.CanWrite && prop.GetIndexParameters().Length == 0 && null != prop.GetSetMethod(/* nonPublic */true)) 
                {
                    memberInfo.Add(Tuple.Create( 
                        Expression.Bind(prop, Expression.Parameter(prop.PropertyType, "placeholder")),
                        ordinal,
                        new EdmProperty(prop.Name, TypeUsage.Create(modelType))));
                } 
            }
            // initialize members in the order in which they appear in the reader 
            MemberInfo[] members = new MemberInfo[memberInfo.Count]; 
            MemberBinding[] memberBindings = new MemberBinding[memberInfo.Count];
            ColumnMap[] propertyMaps = new ColumnMap[memberInfo.Count]; 
            EdmProperty[] modelProperties = new EdmProperty[memberInfo.Count];
            int i = 0;
            foreach (var memberGroup in memberInfo.GroupBy(tuple => tuple.Item2).OrderBy(tuple => tuple.Key))
            { 
                // make sure that a single column isn't contributing to multiple properties
                if (memberGroup.Count() != 1) 
                { 
                    throw EntityUtil.InvalidOperation(Strings.ObjectContext_TwoPropertiesMappedToSameColumn(
                        reader.GetName(memberGroup.Key), 
                        String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray())));
                }

                var member = memberGroup.Single(); 
                MemberAssignment assignment = member.Item1;
                int ordinal = member.Item2; 
                EdmProperty modelProp = member.Item3; 

                members[i] = assignment.Member; 
                memberBindings[i] = assignment;
                propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal);
                modelProperties[i] = modelProp;
                i++; 
            }
            NewExpression newExpr = null == constructor ? Expression.New(type) : Expression.New(constructor); 
            MemberInitExpression init = Expression.MemberInit(newExpr, memberBindings); 
            InitializerMetadata initMetadata = InitializerMetadata.CreateProjectionInitializer(
                (EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init, members); 

            // column map (a collection of rows with InitializerMetadata markup)
            RowType rowType = new RowType(modelProperties, initMetadata);
            RecordColumnMap rowMap = new RecordColumnMap(TypeUsage.Create(rowType), 
                "DefaultTypeProjection", propertyMaps, null);
            CollectionColumnMap collectionMap = new SimpleCollectionColumnMap(rowType.GetCollectionType().TypeUsage, 
                rowType.Name, rowMap, null, null); 
            return collectionMap;
        } 

        /// 
        /// Build the entityColumnMap from a store datareader, a type and an entitySet and
        /// a list ofproperties. 
        /// 
        ///  
        ///  
        /// 
        ///  
        /// 
        private static EntityColumnMap CreateEntityTypeElementColumnMap(
            DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet,
            ColumnMap[] propertyColumnMaps, Dictionary 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 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; 
        }

        /// 
        /// For a given edmType, build an array of scalarColumnMaps that map to the columns 
        /// in the store datareader provided.  Note that we're hooking things up by name, not
        /// by ordinal position. 
        ///  
        /// 
        ///  
        /// 
        private static ColumnMap[] GetColumnMapsForType(DbDataReader storeDataReader, EdmType edmType, Dictionary renameList)
        {
            // First get the list of properties; NOTE: we need to hook up the column by name, 
            // not by position.
            IBaseList members = TypeHelpers.GetAllStructuralMembers(edmType); 
            ColumnMap[] propertyColumnMaps = new ColumnMap[members.Count]; 

            int index = 0; 
            foreach (EdmMember member in members)
            {
                if (!Helper.IsPrimitiveType(member.TypeUsage.EdmType))
                { 
                    throw EntityUtil.InvalidOperation(Strings.ADP_InvalidDataReaderUnableToMaterializeNonPrimitiveType(member.Name, member.TypeUsage.EdmType.FullName));
                } 
 
                int ordinal = GetMemberOrdinalFromReader(storeDataReader, member, edmType, renameList);
 
                propertyColumnMaps[index] = new ScalarColumnMap(member.TypeUsage, member.Name, 0, ordinal);
                index++;
            }
            return propertyColumnMaps; 
        }
 
        private static ScalarColumnMap[] CreateDiscriminatorColumnMaps(DbDataReader storeDataReader, FunctionImportMapping mapping) 
        {
            // choose an arbitrary type for discriminator columns -- the type is not 
            // actually statically known
            EdmType discriminatorType =
                MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String);
            TypeUsage discriminatorTypeUsage = 
                TypeUsage.Create(discriminatorType);
 
            ScalarColumnMap[] discriminatorColumns = new ScalarColumnMap[mapping.DiscriminatorColumns.Count]; 
            for (int i = 0; i < discriminatorColumns.Length; i++)
            { 
                string columnName = mapping.DiscriminatorColumns[i];
                ScalarColumnMap columnMap = new ScalarColumnMap(discriminatorTypeUsage, columnName, 0,
                    GetDiscriminatorOrdinalFromReader(storeDataReader, columnName, mapping.FunctionImport));
                discriminatorColumns[i] = columnMap; 
            }
            return discriminatorColumns; 
        } 

        ///  
        /// Given a store datareader and a member of an edmType, find the column ordinal
        /// in the datareader with the name of the member.
        /// 
        ///  
        /// 
        ///  
        private static int GetMemberOrdinalFromReader(DbDataReader storeDataReader, EdmMember member, EdmType currentType, Dictionary renameList) 
        {
            int result; 
            string memberName = GetRenameForMember(member, currentType, renameList);

            if (!TryGetColumnOrdinalFromReader(storeDataReader, memberName, out result))
            { 
                throw EntityUtil.CommandExecutionDataReaderMissingColumnForType(member, currentType);
            } 
            return result; 
        }
 
        private static string GetRenameForMember(EdmMember member, EdmType currentType, Dictionary renameList)
        {
            // if list is null,
            // or no rename mapping at all, 
            // or partial rename and the member is not specified by the renaming
            // then we return the original member.Name 
            // otherwise we return the mapped one 
            return renameList == null || renameList.Count == 0 || !renameList.Any(m => m.Key == member.Name) ? member.Name : renameList[member.Name].GetRename(currentType);
        } 

        /// 
        /// Given a store datareader, a column name, find the column ordinal
        /// in the datareader with the name of the column. 
        ///
        /// We only have the functionImport provided to include it in the exception 
        /// message. 
        /// 
        ///  
        /// 
        /// 
        /// 
        private static int GetDiscriminatorOrdinalFromReader(DbDataReader storeDataReader, string columnName, EdmFunction functionImport) 
        {
            int result; 
            if (!TryGetColumnOrdinalFromReader(storeDataReader, columnName, out result)) 
            {
                throw EntityUtil.CommandExecutionDataReaderMissinDiscriminatorColumn(columnName, functionImport); 
            }
            return result;
        }
 
        /// 
        /// Given a store datareader and a column name, try to find the column ordinal 
        /// in the datareader with the name of the column. 
        /// 
        ///  
        /// 
        /// 
        /// true if found, false otherwise.
        private static bool TryGetColumnOrdinalFromReader(DbDataReader storeDataReader, string columnName, out int ordinal) 
        {
            if (0 == storeDataReader.FieldCount) 
            { 
                // If there are no fields, there can't be a match (this check avoids
                // an InvalidOperationException on the call to GetOrdinal) 
                ordinal = default(int);
                return false;
            }
 
            // Wrap ordinal lookup for the member so that we can throw a nice exception.
            try 
            { 
                ordinal = storeDataReader.GetOrdinal(columnName);
                return true; 
            }
            catch (IndexOutOfRangeException)
            {
                // No column matching the column name found 
                ordinal = default(int);
                return false; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// @owner  [....] 
// @backupOwner [....]
//----------------------------------------------------------------------------- 
 
using System.Data.Common;
using System.Data.Mapping; 
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data.Common.Utils; 
using System.Linq;
using System.Reflection; 
using System.Linq.Expressions; 
using System.Data.Objects.ELinq;
using System.Data.Entity; 

namespace System.Data.Query.InternalTrees
{
    ///  
    /// Factory methods for prescriptive column map patterns (includes default
    /// column maps for -- soon to be -- public materializer services and function 
    /// mappings). 
    /// 
    internal static class ColumnMapFactory 
    {
        /// 
        /// Creates a column map for the given reader and function mapping.
        ///  
        internal static CollectionColumnMap CreateFunctionImportStructuralTypeColumnMap(DbDataReader storeDataReader, FunctionImportMapping mapping, EntitySet entitySet, StructuralType baseStructuralType)
        { 
            if (mapping.NormalizedEntityTypeMappings.Count == 0) // no explicit mapping; use default non-polymorphic reader 
            {
                // if there is no mapping, create default mapping to root entity type or complex type 
                Debug.Assert(!baseStructuralType.Abstract, "mapping loader must verify abstract types have explicit mapping");

                return CreateColumnMapFromReaderAndType(storeDataReader, baseStructuralType, entitySet, mapping.ReturnTypeColumnsRenameMapping);
            } 

            // the section below deals with the polymorphic entity type mapping for return type 
            EntityType baseEntityType = baseStructuralType as EntityType; 
            Debug.Assert(null != baseEntityType, "We should have entity type here");
 
            // Generate column maps for all discriminators
            ScalarColumnMap[] discriminatorColumns = CreateDiscriminatorColumnMaps(storeDataReader, mapping);

            // Generate default maps for all mapped entity types 
            var mappedEntityTypes = new HashSet(mapping.MappedEntityTypes);
            mappedEntityTypes.Add(baseEntityType); // make sure the base type is represented 
            Dictionary typeChoices = new Dictionary(mappedEntityTypes.Count); 
            ColumnMap[] baseTypeColumnMaps = null;
            foreach (EntityType entityType in mappedEntityTypes) 
            {

                ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, entityType, mapping.ReturnTypeColumnsRenameMapping);
                EntityColumnMap entityColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, entityType, entitySet, propertyColumnMaps, mapping.ReturnTypeColumnsRenameMapping); 
                if (!entityType.Abstract)
                { 
                    typeChoices.Add(entityType, entityColumnMap); 
                }
                if (entityType == baseStructuralType) 
                {
                    baseTypeColumnMaps = propertyColumnMaps;
                }
            } 

            // NOTE: We don't have a null sentinel here, because the stored proc won't 
            //       return one anyway; we'll just presume the data's always there. 
            MultipleDiscriminatorPolymorphicColumnMap polymorphicMap = new MultipleDiscriminatorPolymorphicColumnMap(TypeUsage.Create(baseStructuralType), baseStructuralType.Name, baseTypeColumnMaps, discriminatorColumns, typeChoices, mapping.Discriminate);
            CollectionColumnMap collection = new SimpleCollectionColumnMap(baseStructuralType.GetCollectionType().TypeUsage, baseStructuralType.Name, polymorphicMap, null, null); 
            return collection;
        }

        ///  
        /// Build the collectionColumnMap from a store datareader, a type and an entitySet.
        ///  
        ///  
        /// 
        ///  
        /// 
        internal static CollectionColumnMap CreateColumnMapFromReaderAndType(DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet, Dictionary renameList)
        {
            Debug.Assert(Helper.IsEntityType(edmType) || null == entitySet, "The specified non-null EntitySet is incompatible with the EDM type specified."); 

            // Next, build the ColumnMap directly from the edmType and entitySet provided. 
            ColumnMap[] propertyColumnMaps = GetColumnMapsForType(storeDataReader, edmType, renameList); 
            ColumnMap elementColumnMap = null;
 
            // NOTE: We don't have a null sentinel here, because the stored proc won't
            //       return one anyway; we'll just presume the data's always there.
            if (Helper.IsRowType(edmType))
            { 
                elementColumnMap = new RecordColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null);
            } 
            else if (Helper.IsComplexType(edmType)) 
            {
                elementColumnMap = new ComplexTypeColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null); 
            }
            else if (Helper.IsPrimitiveType(edmType))
            {
                if (storeDataReader.FieldCount != 1) 
                {
                    throw EntityUtil.CommandExecutionDataReaderFieldCountForPrimitiveType(); 
                } 
                elementColumnMap = new ScalarColumnMap(TypeUsage.Create(edmType), edmType.Name, 0, 0);
            } 
            else if (Helper.IsEntityType(edmType))
            {
                elementColumnMap = CreateEntityTypeElementColumnMap(storeDataReader, edmType, entitySet, propertyColumnMaps, null/*renameList*/);
            } 
            else
            { 
                Debug.Assert(false, "unexpected edmType?"); 
            }
            CollectionColumnMap collection = new SimpleCollectionColumnMap(edmType.GetCollectionType().TypeUsage, edmType.Name, elementColumnMap, null, null); 
            return collection;
        }

        ///  
        /// Requires: a public type with a public, default constructor. Returns a column map initializing the type
        /// and all properties of the type with a public setter taking a primitive type and having a corresponding 
        /// column in the reader. 
        /// 
        internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(DbDataReader reader, Type type, MetadataWorkspace workspace) 
        {
            Debug.Assert(null != reader);
            Debug.Assert(null != type);
            Debug.Assert(null != workspace); 

            // we require a default constructor 
            ConstructorInfo constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, 
                null, Type.EmptyTypes, null);
            if (type.IsAbstract || (null == constructor && !type.IsValueType)) 
            {
                throw EntityUtil.InvalidOperation(
                    Strings.ObjectContext_InvalidTypeForStoreQuery(type));
            } 

            // build a LINQ expression used by result assembly to create results 
            var memberInfo = new List>(); 
            foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            { 
                Type propType = prop.PropertyType;
                EdmType modelType;
                int ordinal;
                if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) && 
                    MetadataHelper.TryDetermineCSpaceModelType(propType, workspace, out modelType) &&
                    modelType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType && 
                    prop.CanWrite && prop.GetIndexParameters().Length == 0 && null != prop.GetSetMethod(/* nonPublic */true)) 
                {
                    memberInfo.Add(Tuple.Create( 
                        Expression.Bind(prop, Expression.Parameter(prop.PropertyType, "placeholder")),
                        ordinal,
                        new EdmProperty(prop.Name, TypeUsage.Create(modelType))));
                } 
            }
            // initialize members in the order in which they appear in the reader 
            MemberInfo[] members = new MemberInfo[memberInfo.Count]; 
            MemberBinding[] memberBindings = new MemberBinding[memberInfo.Count];
            ColumnMap[] propertyMaps = new ColumnMap[memberInfo.Count]; 
            EdmProperty[] modelProperties = new EdmProperty[memberInfo.Count];
            int i = 0;
            foreach (var memberGroup in memberInfo.GroupBy(tuple => tuple.Item2).OrderBy(tuple => tuple.Key))
            { 
                // make sure that a single column isn't contributing to multiple properties
                if (memberGroup.Count() != 1) 
                { 
                    throw EntityUtil.InvalidOperation(Strings.ObjectContext_TwoPropertiesMappedToSameColumn(
                        reader.GetName(memberGroup.Key), 
                        String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray())));
                }

                var member = memberGroup.Single(); 
                MemberAssignment assignment = member.Item1;
                int ordinal = member.Item2; 
                EdmProperty modelProp = member.Item3; 

                members[i] = assignment.Member; 
                memberBindings[i] = assignment;
                propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal);
                modelProperties[i] = modelProp;
                i++; 
            }
            NewExpression newExpr = null == constructor ? Expression.New(type) : Expression.New(constructor); 
            MemberInitExpression init = Expression.MemberInit(newExpr, memberBindings); 
            InitializerMetadata initMetadata = InitializerMetadata.CreateProjectionInitializer(
                (EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init, members); 

            // column map (a collection of rows with InitializerMetadata markup)
            RowType rowType = new RowType(modelProperties, initMetadata);
            RecordColumnMap rowMap = new RecordColumnMap(TypeUsage.Create(rowType), 
                "DefaultTypeProjection", propertyMaps, null);
            CollectionColumnMap collectionMap = new SimpleCollectionColumnMap(rowType.GetCollectionType().TypeUsage, 
                rowType.Name, rowMap, null, null); 
            return collectionMap;
        } 

        /// 
        /// Build the entityColumnMap from a store datareader, a type and an entitySet and
        /// a list ofproperties. 
        /// 
        ///  
        ///  
        /// 
        ///  
        /// 
        private static EntityColumnMap CreateEntityTypeElementColumnMap(
            DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet,
            ColumnMap[] propertyColumnMaps, Dictionary 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 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; 
        }

        /// 
        /// For a given edmType, build an array of scalarColumnMaps that map to the columns 
        /// in the store datareader provided.  Note that we're hooking things up by name, not
        /// by ordinal position. 
        ///  
        /// 
        ///  
        /// 
        private static ColumnMap[] GetColumnMapsForType(DbDataReader storeDataReader, EdmType edmType, Dictionary renameList)
        {
            // First get the list of properties; NOTE: we need to hook up the column by name, 
            // not by position.
            IBaseList members = TypeHelpers.GetAllStructuralMembers(edmType); 
            ColumnMap[] propertyColumnMaps = new ColumnMap[members.Count]; 

            int index = 0; 
            foreach (EdmMember member in members)
            {
                if (!Helper.IsPrimitiveType(member.TypeUsage.EdmType))
                { 
                    throw EntityUtil.InvalidOperation(Strings.ADP_InvalidDataReaderUnableToMaterializeNonPrimitiveType(member.Name, member.TypeUsage.EdmType.FullName));
                } 
 
                int ordinal = GetMemberOrdinalFromReader(storeDataReader, member, edmType, renameList);
 
                propertyColumnMaps[index] = new ScalarColumnMap(member.TypeUsage, member.Name, 0, ordinal);
                index++;
            }
            return propertyColumnMaps; 
        }
 
        private static ScalarColumnMap[] CreateDiscriminatorColumnMaps(DbDataReader storeDataReader, FunctionImportMapping mapping) 
        {
            // choose an arbitrary type for discriminator columns -- the type is not 
            // actually statically known
            EdmType discriminatorType =
                MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String);
            TypeUsage discriminatorTypeUsage = 
                TypeUsage.Create(discriminatorType);
 
            ScalarColumnMap[] discriminatorColumns = new ScalarColumnMap[mapping.DiscriminatorColumns.Count]; 
            for (int i = 0; i < discriminatorColumns.Length; i++)
            { 
                string columnName = mapping.DiscriminatorColumns[i];
                ScalarColumnMap columnMap = new ScalarColumnMap(discriminatorTypeUsage, columnName, 0,
                    GetDiscriminatorOrdinalFromReader(storeDataReader, columnName, mapping.FunctionImport));
                discriminatorColumns[i] = columnMap; 
            }
            return discriminatorColumns; 
        } 

        ///  
        /// Given a store datareader and a member of an edmType, find the column ordinal
        /// in the datareader with the name of the member.
        /// 
        ///  
        /// 
        ///  
        private static int GetMemberOrdinalFromReader(DbDataReader storeDataReader, EdmMember member, EdmType currentType, Dictionary renameList) 
        {
            int result; 
            string memberName = GetRenameForMember(member, currentType, renameList);

            if (!TryGetColumnOrdinalFromReader(storeDataReader, memberName, out result))
            { 
                throw EntityUtil.CommandExecutionDataReaderMissingColumnForType(member, currentType);
            } 
            return result; 
        }
 
        private static string GetRenameForMember(EdmMember member, EdmType currentType, Dictionary renameList)
        {
            // if list is null,
            // or no rename mapping at all, 
            // or partial rename and the member is not specified by the renaming
            // then we return the original member.Name 
            // otherwise we return the mapped one 
            return renameList == null || renameList.Count == 0 || !renameList.Any(m => m.Key == member.Name) ? member.Name : renameList[member.Name].GetRename(currentType);
        } 

        /// 
        /// Given a store datareader, a column name, find the column ordinal
        /// in the datareader with the name of the column. 
        ///
        /// We only have the functionImport provided to include it in the exception 
        /// message. 
        /// 
        ///  
        /// 
        /// 
        /// 
        private static int GetDiscriminatorOrdinalFromReader(DbDataReader storeDataReader, string columnName, EdmFunction functionImport) 
        {
            int result; 
            if (!TryGetColumnOrdinalFromReader(storeDataReader, columnName, out result)) 
            {
                throw EntityUtil.CommandExecutionDataReaderMissinDiscriminatorColumn(columnName, functionImport); 
            }
            return result;
        }
 
        /// 
        /// Given a store datareader and a column name, try to find the column ordinal 
        /// in the datareader with the name of the column. 
        /// 
        ///  
        /// 
        /// 
        /// true if found, false otherwise.
        private static bool TryGetColumnOrdinalFromReader(DbDataReader storeDataReader, string columnName, out int ordinal) 
        {
            if (0 == storeDataReader.FieldCount) 
            { 
                // If there are no fields, there can't be a match (this check avoids
                // an InvalidOperationException on the call to GetOrdinal) 
                ordinal = default(int);
                return false;
            }
 
            // Wrap ordinal lookup for the member so that we can throw a nice exception.
            try 
            { 
                ordinal = storeDataReader.GetOrdinal(columnName);
                return true; 
            }
            catch (IndexOutOfRangeException)
            {
                // No column matching the column name found 
                ordinal = default(int);
                return false; 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK