BridgeDataReader.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 / ResultAssembly / BridgeDataReader.cs / 1305376 / BridgeDataReader.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// @owner  [....] 
// @backupOwner [....]
//--------------------------------------------------------------------- 
 
namespace System.Data.Query.ResultAssembly {
 
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data; 
    using System.Data.Common;
    using System.Data.Common.CommandTrees; 
    using System.Data.Common.Internal.Materialization; 
    using System.Data.Metadata.Edm;
    using System.Data.Query.InternalTrees; 
    using System.Data.Query.PlanCompiler;
    using System.Diagnostics;
    using System.Text;
    using System.Threading; 
    using System.Data.Entity;
    using System.Linq; 
    using System.Data.Mapping; 
    using System.Data.Common.Utils;
 
    /// 
    /// DbDataReader functionality for the bridge.
    /// 
    internal sealed class BridgeDataReader : DbDataReader, IExtendedDataRecord { 

        #region private state 
 
        /// 
        /// Object that holds the state needed by the coordinator and the root enumerator 
        /// 
        private readonly Shaper Shaper;

        ///  
        /// The coordinator we're responsible for returning results for.
        ///  
        private readonly CoordinatorFactory CoordinatorFactory; 

        ///  
        /// The default record (pre-read/past-end) state
        /// 
        private readonly RecordState DefaultRecordState;
 
        /// 
        /// We delegate to this on our getters, to avoid duplicate code. 
        ///  
        private readonly BridgeDataRecord DataRecord;
 
        /// 
        /// Do we have a row to read?  Determined in the constructor and
        /// should not be changed.
        ///  
        private readonly bool _hasRows;
 
        ///  
        /// Set to true only when we've been closed through the Close() method
        ///  
        private bool _isClosed;

        #endregion
 
        #region constructors
 
        ///  
        /// Constructor used by the ResultColumn when doing GetValue, and by the Create factory
        /// method. 
        /// 
        /// 
        /// 
        internal BridgeDataReader(Shaper shaper, CoordinatorFactory coordinatorFactory, int depth) 
            : base() {
            Debug.Assert(null != shaper, "null shaper?"); 
            Debug.Assert(null != coordinatorFactory, "null coordinatorFactory?"); 

            Shaper = shaper; 
            CoordinatorFactory = coordinatorFactory;
            DataRecord = new BridgeDataRecord(shaper, depth);

            // To determine whether there are any rows for this coordinator at this place in 
            // the root enumerator, we pretty much just look at it's current record (we'll read
            // one if there isn't one waiting) and if it matches our coordinator, we've got rows. 
            _hasRows = false; 

            if (!Shaper.DataWaiting) { 
                Shaper.DataWaiting = Shaper.RootEnumerator.MoveNext();
            }
            if (Shaper.DataWaiting) {
                RecordState currentRecord = Shaper.RootEnumerator.Current; 

                if (null != currentRecord) { 
                    _hasRows = (currentRecord.CoordinatorFactory == CoordinatorFactory); 
                }
            } 

            // Once we've created the root enumerator, we can get the default record state
            DefaultRecordState = coordinatorFactory.GetDefaultRecordState(Shaper);
            Debug.Assert(null != DefaultRecordState, "no default?"); 
            }
 
        ///  
        /// The primary factory method to produce the BridgeDataReader; given a store data
        /// reader and a column map, create the BridgeDataReader, hooking up the IteratorSources 
        /// and ResultColumn Hierarchy.  All construction of top level data readers go through
        /// this method.
        /// 
        ///  
        /// 
        ///  
        static internal DbDataReader Create(DbDataReader storeDataReader, ColumnMap columnMap, MetadataWorkspace workspace) { 
            Debug.Assert(storeDataReader != null, "null storeDataReaders?");
            Debug.Assert(columnMap != null, "null columnMap?"); 
            Debug.Assert(workspace != null, "null workspace?");

            System.Data.Common.QueryCache.QueryCacheManager cacheManager = workspace.GetQueryCacheManager();
            const System.Data.Objects.MergeOption NoTracking = System.Data.Objects.MergeOption.NoTracking; 

            ShaperFactory shaperFactory = Translator.TranslateColumnMap(cacheManager, columnMap, workspace, null, NoTracking, true); 
            Shaper recordShaper = shaperFactory.Create(storeDataReader, null, workspace, System.Data.Objects.MergeOption.NoTracking, true); 

            DbDataReader result = new BridgeDataReader(recordShaper, recordShaper.RootCoordinator.TypedCoordinatorFactory, 0); 
            return result;
        }

        #endregion 

        #region helpers 
 
        /// 
        /// Implicitly close this (nested) data reader; will be called whenever 
        /// the user has done a GetValue() or a Read() on a parent reader/record
        /// to ensure that we consume all our results.  We do that because we
        /// our design requires us to be positioned at the next nested reader's
        /// first row. 
        /// 
        internal void CloseImplicitly() { 
            Consume(); 
            DataRecord.CloseImplicitly();
        } 

        /// 
        /// Reads to the end of the source enumerator provided
        ///  
        private void Consume() {
            while (ReadInternal()) ; 
        } 

        ///  
        /// Figure out the CLR type from the TypeMetadata object; For scalars,
        /// we can get this from the metadata workspace, but for the rest, we
        /// just guess at "Object".  You need to use the DataRecordInfo property
        /// to get better information for those. 
        /// 
        ///  
        ///  
        internal static Type GetClrTypeFromTypeMetadata(TypeUsage typeUsage) {
            Type result; 

            PrimitiveType primitiveType;
            if (TypeHelpers.TryGetEdmType(typeUsage, out primitiveType)) {
                result = primitiveType.ClrEquivalentType; 
            }
            else { 
                if (TypeSemantics.IsReferenceType(typeUsage)) { 
                    result = typeof(EntityKey);
                } 
                else if (TypeUtils.IsStructuredType(typeUsage)) {
                    result = typeof(DbDataRecord);
                }
                else if (TypeUtils.IsCollectionType(typeUsage)) { 
                    result = typeof(DbDataReader);
                } 
                else { 
                    result = typeof(object);
                } 
            }
            return result;
        }
 
        #endregion
 
        #region data reader specific properties and methods 

        ///  
        /// implementation for DbDataReader.Depth property
        /// 
        override public int Depth {
            get { 
                AssertReaderIsOpen("Depth");
                return DataRecord.Depth; 
            } 
        }
 
        /// 
        /// implementation for DbDataReader.HasRows property
        /// 
        override public bool HasRows { 
            get {
                AssertReaderIsOpen("HasRows"); 
                return _hasRows; 
            }
        } 

        /// 
        /// implementation for DbDataReader.IsClosed property
        ///  
        override public bool IsClosed {
            get { 
                // Rather that try and track this in two places; we just delegate 
                // to the data record that we constructed; it has more reasons to
                // have to know this than we do in the data reader.  (Of course, 
                // we look at our own closed state too...)
                return ((_isClosed) || DataRecord.IsClosed);
            }
        } 

        ///  
        /// implementation for DbDataReader.RecordsAffected property 
        /// 
        override public int RecordsAffected { 
            get {
                int result = -1; // For nested readers, return -1 which is the default for queries.

                // We defer to the store reader for rows affected count. Note that for queries, 
                // the provider is generally expected to return -1.
                // 
                if (DataRecord.Depth == 0) { 
                    result = Shaper.Reader.RecordsAffected;
                } 
                return result;
            }
        }
 
        /// 
        /// Ensures that the reader is actually open, and throws an exception if not 
        ///  
        private void AssertReaderIsOpen(string methodName) {
            if (IsClosed) { 
                if (DataRecord.IsImplicitlyClosed) {
                    throw EntityUtil.ImplicitlyClosedDataReaderError();
                }
                if (DataRecord.IsExplicitlyClosed) { 
                    throw EntityUtil.DataReaderClosed(methodName);
                } 
            } 
        }
 
        /// 
        /// implementation for DbDataReader.Close() method
        /// 
        override public void Close() { 
            // Make sure we explicitly closed the data record, since that's what
            // where using to track closed state. 
            DataRecord.CloseExplicitly(); 

            if (!_isClosed) { 
                _isClosed = true;

                if (0 == DataRecord.Depth) {
                    // If we're the root collection, we want to ensure the remainder of 
                    // the result column hierarchy is closed out, to avoid dangling
                    // references to it, should it be reused. We also want to physically 
                    // close out the source reader as well. 
                    Shaper.Reader.Close();
                } 
                else {
                    // For non-root collections, we have to consume all the data, or we'll
                    // not be positioned propertly for what comes afterward.
                    Consume(); 
                }
            } 
        } 

        ///  
        /// implementation for DbDataReader.GetEnumerator() method
        /// 
        [EditorBrowsableAttribute(EditorBrowsableState.Never)]
        override public IEnumerator GetEnumerator() { 
            IEnumerator result = new DbEnumerator((IDataReader)this, true); // We always want to close the reader;
            return result; 
        } 

        ///  
        /// implementation for DbDataReader.GetSchemaTable() method
        ///
        /// This is awaiting some common code
        ///  
        /// 
        /// GetSchemaTable is not supported at this time 
        override public DataTable GetSchemaTable() { 
            throw EntityUtil.NotSupported(System.Data.Entity.Strings.ADP_GetSchemaTableIsNotSupported);
        } 

        /// 
        /// implementation for DbDataReader.NextResult() method
        /// 
        /// since the bridge currently doesn't support multiple results in a
        /// single command, this always returns false. 
        ///  
        /// 
        override public bool NextResult() { 
            AssertReaderIsOpen("NextResult");

            // Consume results in the source collection to ensure that the
            // store reader and the bridge data reader are in the same state. 
            // If we are not a root reader, we do not 'own' the store reader
            // and do nothing. 
 
            if (0 == DataRecord.Depth) {
                // NOTE:: this is required to ensure that output parameter values 
                // are set in SQL Server, and other providers where they come after
                // the results.
                CommandHelper.ConsumeReader(Shaper.Reader);
            } 
            else {
                // For nested readers, make sure we're positioned properly for 
                // the following columns... 
                Consume();
            } 

            // SQLBUDT #631726 - ensure we close the records that may be
            // outstanding...
            // SQLBUDT #632494 - do this after we consume the underlying reader 
            // so we don't run result assembly through it...
            CloseImplicitly(); 
 
            // Reset any state on our attached data record, since we've now
            // gone past the end of the reader. 
            DataRecord.SetRecordSource(null, false);

            // NOTE: if the bridge ever supports multiple results in a single
            //       command, we'll need to change this, but for now we can't 
            //       ever have another result.
            return false; 
        } 

        ///  
        /// implementation for DbDataReader.Read() method
        /// 
        /// 
        override public bool Read() { 
            AssertReaderIsOpen("Read");
 
            // First of all we need to inform each of the nested records that 
            // have been returned that they're "implicitly" closed -- that is
            // we've moved on.  This will also ensure that any records remaining 
            // in any active nested readers are consumed
            DataRecord.CloseImplicitly();

            // OK, now go ahead and advance the source enumerator and set the 
            // record source up
            bool result = ReadInternal(); 
            DataRecord.SetRecordSource(Shaper.RootEnumerator.Current, result); 
            return result;
        } 

        /// 
        /// Internal read method; does the work of advancing the root enumerator
        /// as needed and determining whether it's current record is for our 
        /// coordinator.  The public Read method does the assertions and such that
        /// we don't want to do when we're called from internal methods to do things 
        /// like consume the rest of the reader's contents. 
        /// 
        ///  
        /// 
        private bool ReadInternal() {
            bool result = false;
 
            // If there's nothing waiting for the root enumerator, then attempt
            // to advance it. 
            if (!Shaper.DataWaiting) { 
                Shaper.DataWaiting = Shaper.RootEnumerator.MoveNext();
            } 

            // If we have some data (we may have just read it above) then figure
            // out who it belongs to-- us or someone else. We also skip over any
            // records that are for our children (nested readers); if we're being 
            // asked to read, it's too late for them to read them.
            while (Shaper.DataWaiting 
                        && Shaper.RootEnumerator.Current.CoordinatorFactory != CoordinatorFactory 
                        && Shaper.RootEnumerator.Current.CoordinatorFactory.Depth > CoordinatorFactory.Depth) {
                Shaper.DataWaiting = Shaper.RootEnumerator.MoveNext(); 
            }

            if (Shaper.DataWaiting) {
                // We found something, go ahead and indicate to the shaper we want 
                // this record, set up the data record, etc.
                if (Shaper.RootEnumerator.Current.CoordinatorFactory == CoordinatorFactory) { 
                    Shaper.DataWaiting = false; 
                    Shaper.RootEnumerator.Current.AcceptPendingValues();
                    result = true; 
                }
            }
            return result;
        } 

        #endregion 
 
        #region metadata properties and methods
 
        /// 
        /// implementation for DbDataReader.DataRecordInfo property
        /// 
        public DataRecordInfo DataRecordInfo { 
            get {
                AssertReaderIsOpen("DataRecordInfo"); 
 
                DataRecordInfo result;
                if (DataRecord.HasData) { 
                    result = DataRecord.DataRecordInfo;
                }
                else {
                    result = DefaultRecordState.DataRecordInfo; 
                }
                return result; 
            } 
        }
 
        /// 
        /// implementation for DbDataReader.FieldCount property
        /// 
        override public int FieldCount { 
            get {
                AssertReaderIsOpen("FieldCount"); 
 
                // In this method, we need to return a constant value, regardless
                // of how polymorphic the result is, because there is a lot of code 
                // in the wild that expects it to be constant; Ideally, we'd return
                // the number of columns in the actual type that we have, but since
                // that would probably break folks, I'm leaving it at returning the
                // base set of columns that all rows will have. 

                int result = DefaultRecordState.ColumnCount; 
                return result; 
            }
        } 

        /// 
        /// implementation for DbDataReader.GetDataTypeName() method
        ///  
        /// 
        ///  
        override public string GetDataTypeName(int ordinal) { 
            AssertReaderIsOpen("GetDataTypeName");
            string result; 
            if (DataRecord.HasData) {
                result = DataRecord.GetDataTypeName(ordinal);
            }
            else { 
                result = TypeHelpers.GetFullName(DefaultRecordState.GetTypeUsage(ordinal));
            } 
            return result; 
        }
 
        /// 
        /// implementation for DbDataReader.GetFieldType() method
        /// 
        ///  
        /// 
        override public Type GetFieldType(int ordinal) { 
            AssertReaderIsOpen("GetFieldType"); 
            Type result;
            if (DataRecord.HasData) { 
                result = DataRecord.GetFieldType(ordinal);
            }
            else {
                result = GetClrTypeFromTypeMetadata(DefaultRecordState.GetTypeUsage(ordinal)); 
            }
            return result; 
        } 

        ///  
        /// implementation for DbDataReader.GetName() method
        /// 
        /// 
        ///  
        override public string GetName(int ordinal) {
            AssertReaderIsOpen("GetName"); 
            string result; 
            if (DataRecord.HasData) {
                result = DataRecord.GetName(ordinal); 
            }
            else {
                result = DefaultRecordState.GetName(ordinal);
            } 
            return result;
        } 
 
        /// 
        /// implementation for DbDataReader.GetOrdinal() method 
        /// 
        /// 
        /// 
 
        override public int GetOrdinal(string name) {
            AssertReaderIsOpen("GetOrdinal"); 
            int result; 
            if (DataRecord.HasData) {
                result = DataRecord.GetOrdinal(name); 
            }
            else {
                result = DefaultRecordState.GetOrdinal(name);
            } 
            return result;
        } 
 
        /// 
        /// implementation for DbDataReader.GetProviderSpecificFieldType() method 
        /// 
        /// 
        /// 
        /// GetProviderSpecificFieldType is not supported at this time 
        [EditorBrowsableAttribute(EditorBrowsableState.Never)]
        override public Type GetProviderSpecificFieldType(int ordinal) { 
            throw EntityUtil.NotSupported(); 
        }
 
        #endregion

        #region data record properties and methods
 
        ////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////// 
        //////////////////////////////////////////////////////////////////////// 
        //
        // The remaining methods on this class delegate to the inner data record 
        //
        ////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////// 

        #region general getter methods and indexer properties 
 
        /// 
        /// implementation for DbDataReader[ordinal] indexer value getter 
        /// 
        override public object this[int ordinal] {
            get {
                return DataRecord[ordinal]; 
            }
        } 
 
        /// 
        /// implementation for DbDataReader[name] indexer value getter 
        /// 
        override public object this[string name] {
            get {
                int ordinal = GetOrdinal(name); 
                return DataRecord[ordinal];
            } 
        } 

        ///  
        /// implementation for DbDataReader.GetProviderSpecificValue() method
        /// 
        /// 
        ///  
        /// GetProviderSpecificValue is not supported at this time
        [EditorBrowsableAttribute(EditorBrowsableState.Never)] 
        public override object GetProviderSpecificValue(int ordinal) { 
            throw EntityUtil.NotSupported();
        } 

        /// 
        /// implementation for DbDataReader.GetProviderSpecificValues() method
        ///  
        /// 
        ///  
        /// GetProviderSpecificValues is not supported at this time 
        [EditorBrowsableAttribute(EditorBrowsableState.Never)]
        public override int GetProviderSpecificValues(object[] values) { 
            throw EntityUtil.NotSupported();
        }

        ///  
        /// implementation for DbDataReader.GetValue() method
        ///  
        ///  
        /// 
        override public Object GetValue(int ordinal) { 
            return DataRecord.GetValue(ordinal);
        }

        ///  
        /// implementation for DbDataReader.GetValues() method
        ///  
        ///  
        /// 
        override public int GetValues(object[] values) { 
            return DataRecord.GetValues(values);
        }

        #endregion 

        #region simple scalar value getter methods 
 
        /// 
        /// implementation for DbDataReader.GetBoolean() method 
        /// 
        /// 
        /// 
        override public bool GetBoolean(int ordinal) { 
            return DataRecord.GetBoolean(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetByte() method 
        /// 
        /// 
        /// 
        override public byte GetByte(int ordinal) { 
            return DataRecord.GetByte(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetChar() method 
        /// 
        /// 
        /// 
        override public char GetChar(int ordinal) { 
            return DataRecord.GetChar(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetDateTime() method 
        /// 
        /// 
        /// 
        override public DateTime GetDateTime(int ordinal) { 
            return DataRecord.GetDateTime(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetDecimal() method 
        /// 
        /// 
        /// 
        override public Decimal GetDecimal(int ordinal) { 
            return DataRecord.GetDecimal(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetDouble() method 
        /// 
        /// 
        /// 
        override public double GetDouble(int ordinal) { 
            return DataRecord.GetDouble(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetFloat() method 
        /// 
        /// 
        /// 
        override public float GetFloat(int ordinal) { 
            return DataRecord.GetFloat(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetGuid() method 
        /// 
        /// 
        /// 
        override public Guid GetGuid(int ordinal) { 
            return DataRecord.GetGuid(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetInt16() method 
        /// 
        /// 
        /// 
        override public Int16 GetInt16(int ordinal) { 
            return DataRecord.GetInt16(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetInt32() method 
        /// 
        /// 
        /// 
        override public Int32 GetInt32(int ordinal) { 
            return DataRecord.GetInt32(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetInt64() method 
        /// 
        /// 
        /// 
        override public Int64 GetInt64(int ordinal) { 
            return DataRecord.GetInt64(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetString() method 
        /// 
        /// 
        /// 
        override public String GetString(int ordinal) { 
            return DataRecord.GetString(ordinal);
        } 
 

        ///  
        /// implementation for DbDataReader.IsDBNull() method
        /// 
        /// 
        ///  
        override public bool IsDBNull(int ordinal) {
            return DataRecord.IsDBNull(ordinal); 
        } 

        #endregion 

        #region chunking scalar value getter methods

        ///  
        /// implementation for DbDataReader.GetBytes() method
        ///  
        ///  
        /// 
        ///  
        /// 
        /// 
        /// 
        override public long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) { 
            return DataRecord.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length);
        } 
 
        /// 
        /// implementation for DbDataReader.GetChars() method 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        override public long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) {
            return DataRecord.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); 
        }

        #endregion
 
        #region complex type getters
 
        ///  
        /// implementation for DbDataReader.GetData() method
        ///  
        /// 
        /// 
        override protected DbDataReader GetDbDataReader(int ordinal) {
            return (DbDataReader)DataRecord.GetData(ordinal); 
        }
 
        ///  
        /// implementation for DbDataReader.GetDataRecord() method
        ///  
        /// 
        /// 
        public DbDataRecord GetDataRecord(int ordinal) {
            return DataRecord.GetDataRecord(ordinal); 
        }
 
        ///  
        /// Used to return a nested result
        ///  
        /// 
        /// 
        public DbDataReader GetDataReader(int ordinal) {
            return this.GetDbDataReader(ordinal); 
        }
 
        #endregion 

        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// @owner  [....] 
// @backupOwner [....]
//--------------------------------------------------------------------- 
 
namespace System.Data.Query.ResultAssembly {
 
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data; 
    using System.Data.Common;
    using System.Data.Common.CommandTrees; 
    using System.Data.Common.Internal.Materialization; 
    using System.Data.Metadata.Edm;
    using System.Data.Query.InternalTrees; 
    using System.Data.Query.PlanCompiler;
    using System.Diagnostics;
    using System.Text;
    using System.Threading; 
    using System.Data.Entity;
    using System.Linq; 
    using System.Data.Mapping; 
    using System.Data.Common.Utils;
 
    /// 
    /// DbDataReader functionality for the bridge.
    /// 
    internal sealed class BridgeDataReader : DbDataReader, IExtendedDataRecord { 

        #region private state 
 
        /// 
        /// Object that holds the state needed by the coordinator and the root enumerator 
        /// 
        private readonly Shaper Shaper;

        ///  
        /// The coordinator we're responsible for returning results for.
        ///  
        private readonly CoordinatorFactory CoordinatorFactory; 

        ///  
        /// The default record (pre-read/past-end) state
        /// 
        private readonly RecordState DefaultRecordState;
 
        /// 
        /// We delegate to this on our getters, to avoid duplicate code. 
        ///  
        private readonly BridgeDataRecord DataRecord;
 
        /// 
        /// Do we have a row to read?  Determined in the constructor and
        /// should not be changed.
        ///  
        private readonly bool _hasRows;
 
        ///  
        /// Set to true only when we've been closed through the Close() method
        ///  
        private bool _isClosed;

        #endregion
 
        #region constructors
 
        ///  
        /// Constructor used by the ResultColumn when doing GetValue, and by the Create factory
        /// method. 
        /// 
        /// 
        /// 
        internal BridgeDataReader(Shaper shaper, CoordinatorFactory coordinatorFactory, int depth) 
            : base() {
            Debug.Assert(null != shaper, "null shaper?"); 
            Debug.Assert(null != coordinatorFactory, "null coordinatorFactory?"); 

            Shaper = shaper; 
            CoordinatorFactory = coordinatorFactory;
            DataRecord = new BridgeDataRecord(shaper, depth);

            // To determine whether there are any rows for this coordinator at this place in 
            // the root enumerator, we pretty much just look at it's current record (we'll read
            // one if there isn't one waiting) and if it matches our coordinator, we've got rows. 
            _hasRows = false; 

            if (!Shaper.DataWaiting) { 
                Shaper.DataWaiting = Shaper.RootEnumerator.MoveNext();
            }
            if (Shaper.DataWaiting) {
                RecordState currentRecord = Shaper.RootEnumerator.Current; 

                if (null != currentRecord) { 
                    _hasRows = (currentRecord.CoordinatorFactory == CoordinatorFactory); 
                }
            } 

            // Once we've created the root enumerator, we can get the default record state
            DefaultRecordState = coordinatorFactory.GetDefaultRecordState(Shaper);
            Debug.Assert(null != DefaultRecordState, "no default?"); 
            }
 
        ///  
        /// The primary factory method to produce the BridgeDataReader; given a store data
        /// reader and a column map, create the BridgeDataReader, hooking up the IteratorSources 
        /// and ResultColumn Hierarchy.  All construction of top level data readers go through
        /// this method.
        /// 
        ///  
        /// 
        ///  
        static internal DbDataReader Create(DbDataReader storeDataReader, ColumnMap columnMap, MetadataWorkspace workspace) { 
            Debug.Assert(storeDataReader != null, "null storeDataReaders?");
            Debug.Assert(columnMap != null, "null columnMap?"); 
            Debug.Assert(workspace != null, "null workspace?");

            System.Data.Common.QueryCache.QueryCacheManager cacheManager = workspace.GetQueryCacheManager();
            const System.Data.Objects.MergeOption NoTracking = System.Data.Objects.MergeOption.NoTracking; 

            ShaperFactory shaperFactory = Translator.TranslateColumnMap(cacheManager, columnMap, workspace, null, NoTracking, true); 
            Shaper recordShaper = shaperFactory.Create(storeDataReader, null, workspace, System.Data.Objects.MergeOption.NoTracking, true); 

            DbDataReader result = new BridgeDataReader(recordShaper, recordShaper.RootCoordinator.TypedCoordinatorFactory, 0); 
            return result;
        }

        #endregion 

        #region helpers 
 
        /// 
        /// Implicitly close this (nested) data reader; will be called whenever 
        /// the user has done a GetValue() or a Read() on a parent reader/record
        /// to ensure that we consume all our results.  We do that because we
        /// our design requires us to be positioned at the next nested reader's
        /// first row. 
        /// 
        internal void CloseImplicitly() { 
            Consume(); 
            DataRecord.CloseImplicitly();
        } 

        /// 
        /// Reads to the end of the source enumerator provided
        ///  
        private void Consume() {
            while (ReadInternal()) ; 
        } 

        ///  
        /// Figure out the CLR type from the TypeMetadata object; For scalars,
        /// we can get this from the metadata workspace, but for the rest, we
        /// just guess at "Object".  You need to use the DataRecordInfo property
        /// to get better information for those. 
        /// 
        ///  
        ///  
        internal static Type GetClrTypeFromTypeMetadata(TypeUsage typeUsage) {
            Type result; 

            PrimitiveType primitiveType;
            if (TypeHelpers.TryGetEdmType(typeUsage, out primitiveType)) {
                result = primitiveType.ClrEquivalentType; 
            }
            else { 
                if (TypeSemantics.IsReferenceType(typeUsage)) { 
                    result = typeof(EntityKey);
                } 
                else if (TypeUtils.IsStructuredType(typeUsage)) {
                    result = typeof(DbDataRecord);
                }
                else if (TypeUtils.IsCollectionType(typeUsage)) { 
                    result = typeof(DbDataReader);
                } 
                else { 
                    result = typeof(object);
                } 
            }
            return result;
        }
 
        #endregion
 
        #region data reader specific properties and methods 

        ///  
        /// implementation for DbDataReader.Depth property
        /// 
        override public int Depth {
            get { 
                AssertReaderIsOpen("Depth");
                return DataRecord.Depth; 
            } 
        }
 
        /// 
        /// implementation for DbDataReader.HasRows property
        /// 
        override public bool HasRows { 
            get {
                AssertReaderIsOpen("HasRows"); 
                return _hasRows; 
            }
        } 

        /// 
        /// implementation for DbDataReader.IsClosed property
        ///  
        override public bool IsClosed {
            get { 
                // Rather that try and track this in two places; we just delegate 
                // to the data record that we constructed; it has more reasons to
                // have to know this than we do in the data reader.  (Of course, 
                // we look at our own closed state too...)
                return ((_isClosed) || DataRecord.IsClosed);
            }
        } 

        ///  
        /// implementation for DbDataReader.RecordsAffected property 
        /// 
        override public int RecordsAffected { 
            get {
                int result = -1; // For nested readers, return -1 which is the default for queries.

                // We defer to the store reader for rows affected count. Note that for queries, 
                // the provider is generally expected to return -1.
                // 
                if (DataRecord.Depth == 0) { 
                    result = Shaper.Reader.RecordsAffected;
                } 
                return result;
            }
        }
 
        /// 
        /// Ensures that the reader is actually open, and throws an exception if not 
        ///  
        private void AssertReaderIsOpen(string methodName) {
            if (IsClosed) { 
                if (DataRecord.IsImplicitlyClosed) {
                    throw EntityUtil.ImplicitlyClosedDataReaderError();
                }
                if (DataRecord.IsExplicitlyClosed) { 
                    throw EntityUtil.DataReaderClosed(methodName);
                } 
            } 
        }
 
        /// 
        /// implementation for DbDataReader.Close() method
        /// 
        override public void Close() { 
            // Make sure we explicitly closed the data record, since that's what
            // where using to track closed state. 
            DataRecord.CloseExplicitly(); 

            if (!_isClosed) { 
                _isClosed = true;

                if (0 == DataRecord.Depth) {
                    // If we're the root collection, we want to ensure the remainder of 
                    // the result column hierarchy is closed out, to avoid dangling
                    // references to it, should it be reused. We also want to physically 
                    // close out the source reader as well. 
                    Shaper.Reader.Close();
                } 
                else {
                    // For non-root collections, we have to consume all the data, or we'll
                    // not be positioned propertly for what comes afterward.
                    Consume(); 
                }
            } 
        } 

        ///  
        /// implementation for DbDataReader.GetEnumerator() method
        /// 
        [EditorBrowsableAttribute(EditorBrowsableState.Never)]
        override public IEnumerator GetEnumerator() { 
            IEnumerator result = new DbEnumerator((IDataReader)this, true); // We always want to close the reader;
            return result; 
        } 

        ///  
        /// implementation for DbDataReader.GetSchemaTable() method
        ///
        /// This is awaiting some common code
        ///  
        /// 
        /// GetSchemaTable is not supported at this time 
        override public DataTable GetSchemaTable() { 
            throw EntityUtil.NotSupported(System.Data.Entity.Strings.ADP_GetSchemaTableIsNotSupported);
        } 

        /// 
        /// implementation for DbDataReader.NextResult() method
        /// 
        /// since the bridge currently doesn't support multiple results in a
        /// single command, this always returns false. 
        ///  
        /// 
        override public bool NextResult() { 
            AssertReaderIsOpen("NextResult");

            // Consume results in the source collection to ensure that the
            // store reader and the bridge data reader are in the same state. 
            // If we are not a root reader, we do not 'own' the store reader
            // and do nothing. 
 
            if (0 == DataRecord.Depth) {
                // NOTE:: this is required to ensure that output parameter values 
                // are set in SQL Server, and other providers where they come after
                // the results.
                CommandHelper.ConsumeReader(Shaper.Reader);
            } 
            else {
                // For nested readers, make sure we're positioned properly for 
                // the following columns... 
                Consume();
            } 

            // SQLBUDT #631726 - ensure we close the records that may be
            // outstanding...
            // SQLBUDT #632494 - do this after we consume the underlying reader 
            // so we don't run result assembly through it...
            CloseImplicitly(); 
 
            // Reset any state on our attached data record, since we've now
            // gone past the end of the reader. 
            DataRecord.SetRecordSource(null, false);

            // NOTE: if the bridge ever supports multiple results in a single
            //       command, we'll need to change this, but for now we can't 
            //       ever have another result.
            return false; 
        } 

        ///  
        /// implementation for DbDataReader.Read() method
        /// 
        /// 
        override public bool Read() { 
            AssertReaderIsOpen("Read");
 
            // First of all we need to inform each of the nested records that 
            // have been returned that they're "implicitly" closed -- that is
            // we've moved on.  This will also ensure that any records remaining 
            // in any active nested readers are consumed
            DataRecord.CloseImplicitly();

            // OK, now go ahead and advance the source enumerator and set the 
            // record source up
            bool result = ReadInternal(); 
            DataRecord.SetRecordSource(Shaper.RootEnumerator.Current, result); 
            return result;
        } 

        /// 
        /// Internal read method; does the work of advancing the root enumerator
        /// as needed and determining whether it's current record is for our 
        /// coordinator.  The public Read method does the assertions and such that
        /// we don't want to do when we're called from internal methods to do things 
        /// like consume the rest of the reader's contents. 
        /// 
        ///  
        /// 
        private bool ReadInternal() {
            bool result = false;
 
            // If there's nothing waiting for the root enumerator, then attempt
            // to advance it. 
            if (!Shaper.DataWaiting) { 
                Shaper.DataWaiting = Shaper.RootEnumerator.MoveNext();
            } 

            // If we have some data (we may have just read it above) then figure
            // out who it belongs to-- us or someone else. We also skip over any
            // records that are for our children (nested readers); if we're being 
            // asked to read, it's too late for them to read them.
            while (Shaper.DataWaiting 
                        && Shaper.RootEnumerator.Current.CoordinatorFactory != CoordinatorFactory 
                        && Shaper.RootEnumerator.Current.CoordinatorFactory.Depth > CoordinatorFactory.Depth) {
                Shaper.DataWaiting = Shaper.RootEnumerator.MoveNext(); 
            }

            if (Shaper.DataWaiting) {
                // We found something, go ahead and indicate to the shaper we want 
                // this record, set up the data record, etc.
                if (Shaper.RootEnumerator.Current.CoordinatorFactory == CoordinatorFactory) { 
                    Shaper.DataWaiting = false; 
                    Shaper.RootEnumerator.Current.AcceptPendingValues();
                    result = true; 
                }
            }
            return result;
        } 

        #endregion 
 
        #region metadata properties and methods
 
        /// 
        /// implementation for DbDataReader.DataRecordInfo property
        /// 
        public DataRecordInfo DataRecordInfo { 
            get {
                AssertReaderIsOpen("DataRecordInfo"); 
 
                DataRecordInfo result;
                if (DataRecord.HasData) { 
                    result = DataRecord.DataRecordInfo;
                }
                else {
                    result = DefaultRecordState.DataRecordInfo; 
                }
                return result; 
            } 
        }
 
        /// 
        /// implementation for DbDataReader.FieldCount property
        /// 
        override public int FieldCount { 
            get {
                AssertReaderIsOpen("FieldCount"); 
 
                // In this method, we need to return a constant value, regardless
                // of how polymorphic the result is, because there is a lot of code 
                // in the wild that expects it to be constant; Ideally, we'd return
                // the number of columns in the actual type that we have, but since
                // that would probably break folks, I'm leaving it at returning the
                // base set of columns that all rows will have. 

                int result = DefaultRecordState.ColumnCount; 
                return result; 
            }
        } 

        /// 
        /// implementation for DbDataReader.GetDataTypeName() method
        ///  
        /// 
        ///  
        override public string GetDataTypeName(int ordinal) { 
            AssertReaderIsOpen("GetDataTypeName");
            string result; 
            if (DataRecord.HasData) {
                result = DataRecord.GetDataTypeName(ordinal);
            }
            else { 
                result = TypeHelpers.GetFullName(DefaultRecordState.GetTypeUsage(ordinal));
            } 
            return result; 
        }
 
        /// 
        /// implementation for DbDataReader.GetFieldType() method
        /// 
        ///  
        /// 
        override public Type GetFieldType(int ordinal) { 
            AssertReaderIsOpen("GetFieldType"); 
            Type result;
            if (DataRecord.HasData) { 
                result = DataRecord.GetFieldType(ordinal);
            }
            else {
                result = GetClrTypeFromTypeMetadata(DefaultRecordState.GetTypeUsage(ordinal)); 
            }
            return result; 
        } 

        ///  
        /// implementation for DbDataReader.GetName() method
        /// 
        /// 
        ///  
        override public string GetName(int ordinal) {
            AssertReaderIsOpen("GetName"); 
            string result; 
            if (DataRecord.HasData) {
                result = DataRecord.GetName(ordinal); 
            }
            else {
                result = DefaultRecordState.GetName(ordinal);
            } 
            return result;
        } 
 
        /// 
        /// implementation for DbDataReader.GetOrdinal() method 
        /// 
        /// 
        /// 
 
        override public int GetOrdinal(string name) {
            AssertReaderIsOpen("GetOrdinal"); 
            int result; 
            if (DataRecord.HasData) {
                result = DataRecord.GetOrdinal(name); 
            }
            else {
                result = DefaultRecordState.GetOrdinal(name);
            } 
            return result;
        } 
 
        /// 
        /// implementation for DbDataReader.GetProviderSpecificFieldType() method 
        /// 
        /// 
        /// 
        /// GetProviderSpecificFieldType is not supported at this time 
        [EditorBrowsableAttribute(EditorBrowsableState.Never)]
        override public Type GetProviderSpecificFieldType(int ordinal) { 
            throw EntityUtil.NotSupported(); 
        }
 
        #endregion

        #region data record properties and methods
 
        ////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////// 
        //////////////////////////////////////////////////////////////////////// 
        //
        // The remaining methods on this class delegate to the inner data record 
        //
        ////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////// 

        #region general getter methods and indexer properties 
 
        /// 
        /// implementation for DbDataReader[ordinal] indexer value getter 
        /// 
        override public object this[int ordinal] {
            get {
                return DataRecord[ordinal]; 
            }
        } 
 
        /// 
        /// implementation for DbDataReader[name] indexer value getter 
        /// 
        override public object this[string name] {
            get {
                int ordinal = GetOrdinal(name); 
                return DataRecord[ordinal];
            } 
        } 

        ///  
        /// implementation for DbDataReader.GetProviderSpecificValue() method
        /// 
        /// 
        ///  
        /// GetProviderSpecificValue is not supported at this time
        [EditorBrowsableAttribute(EditorBrowsableState.Never)] 
        public override object GetProviderSpecificValue(int ordinal) { 
            throw EntityUtil.NotSupported();
        } 

        /// 
        /// implementation for DbDataReader.GetProviderSpecificValues() method
        ///  
        /// 
        ///  
        /// GetProviderSpecificValues is not supported at this time 
        [EditorBrowsableAttribute(EditorBrowsableState.Never)]
        public override int GetProviderSpecificValues(object[] values) { 
            throw EntityUtil.NotSupported();
        }

        ///  
        /// implementation for DbDataReader.GetValue() method
        ///  
        ///  
        /// 
        override public Object GetValue(int ordinal) { 
            return DataRecord.GetValue(ordinal);
        }

        ///  
        /// implementation for DbDataReader.GetValues() method
        ///  
        ///  
        /// 
        override public int GetValues(object[] values) { 
            return DataRecord.GetValues(values);
        }

        #endregion 

        #region simple scalar value getter methods 
 
        /// 
        /// implementation for DbDataReader.GetBoolean() method 
        /// 
        /// 
        /// 
        override public bool GetBoolean(int ordinal) { 
            return DataRecord.GetBoolean(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetByte() method 
        /// 
        /// 
        /// 
        override public byte GetByte(int ordinal) { 
            return DataRecord.GetByte(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetChar() method 
        /// 
        /// 
        /// 
        override public char GetChar(int ordinal) { 
            return DataRecord.GetChar(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetDateTime() method 
        /// 
        /// 
        /// 
        override public DateTime GetDateTime(int ordinal) { 
            return DataRecord.GetDateTime(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetDecimal() method 
        /// 
        /// 
        /// 
        override public Decimal GetDecimal(int ordinal) { 
            return DataRecord.GetDecimal(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetDouble() method 
        /// 
        /// 
        /// 
        override public double GetDouble(int ordinal) { 
            return DataRecord.GetDouble(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetFloat() method 
        /// 
        /// 
        /// 
        override public float GetFloat(int ordinal) { 
            return DataRecord.GetFloat(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetGuid() method 
        /// 
        /// 
        /// 
        override public Guid GetGuid(int ordinal) { 
            return DataRecord.GetGuid(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetInt16() method 
        /// 
        /// 
        /// 
        override public Int16 GetInt16(int ordinal) { 
            return DataRecord.GetInt16(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetInt32() method 
        /// 
        /// 
        /// 
        override public Int32 GetInt32(int ordinal) { 
            return DataRecord.GetInt32(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetInt64() method 
        /// 
        /// 
        /// 
        override public Int64 GetInt64(int ordinal) { 
            return DataRecord.GetInt64(ordinal);
        } 
 
        /// 
        /// implementation for DbDataReader.GetString() method 
        /// 
        /// 
        /// 
        override public String GetString(int ordinal) { 
            return DataRecord.GetString(ordinal);
        } 
 

        ///  
        /// implementation for DbDataReader.IsDBNull() method
        /// 
        /// 
        ///  
        override public bool IsDBNull(int ordinal) {
            return DataRecord.IsDBNull(ordinal); 
        } 

        #endregion 

        #region chunking scalar value getter methods

        ///  
        /// implementation for DbDataReader.GetBytes() method
        ///  
        ///  
        /// 
        ///  
        /// 
        /// 
        /// 
        override public long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) { 
            return DataRecord.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length);
        } 
 
        /// 
        /// implementation for DbDataReader.GetChars() method 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        override public long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) {
            return DataRecord.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); 
        }

        #endregion
 
        #region complex type getters
 
        ///  
        /// implementation for DbDataReader.GetData() method
        ///  
        /// 
        /// 
        override protected DbDataReader GetDbDataReader(int ordinal) {
            return (DbDataReader)DataRecord.GetData(ordinal); 
        }
 
        ///  
        /// implementation for DbDataReader.GetDataRecord() method
        ///  
        /// 
        /// 
        public DbDataRecord GetDataRecord(int ordinal) {
            return DataRecord.GetDataRecord(ordinal); 
        }
 
        ///  
        /// Used to return a nested result
        ///  
        /// 
        /// 
        public DbDataReader GetDataReader(int ordinal) {
            return this.GetDbDataReader(ordinal); 
        }
 
        #endregion 

        #endregion 
    }
}

// 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