using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data; using System.Data.Common; using System.Diagnostics; using System.Globalization; using Microsoft.Data.SqlClient; namespace Umbraco.Cms.Infrastructure.Persistence { /// /// A base implementation of that is suitable for . /// /// /// /// Borrowed from Microsoft: /// See: https://blogs.msdn.microsoft.com/anthonybloesch/2013/01/23/bulk-loading-data-with-idatareader-and-sqlbulkcopy/ /// /// This implementation is designed to be very memory efficient requiring few memory resources and to support /// rapid transfer of data to SQL Server. /// /// Subclasses should implement , , /// , , . /// If they contain disposable resources they should override . /// /// SD: Alternatively, we could have used a LinqEntityDataReader which is nicer to use but it uses quite a lot of reflection and /// I thought this would just be quicker. /// Simple example of that: https://github.com/gridsum/DataflowEx/blob/master/Gridsum.DataflowEx/Databases/BulkDataReader.cs /// Full example of that: https://github.com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs /// So we know where to find that if we ever need it, these would convert any Linq data source to an IDataReader /// /// internal abstract class BulkDataReader : IDataReader { #region Fields /// /// The containing the input row set's schema information /// requires to function correctly. /// private DataTable _schemaTable = new DataTable(); /// /// The mapping from the row set input to the target table's columns. /// private List _columnMappings = new List(); #endregion #region Subclass utility routines /// /// The mapping from the row set input to the target table's columns. /// /// /// If necessary, will be called to initialize the mapping. /// public ReadOnlyCollection ColumnMappings { get { if (this._columnMappings.Count == 0) { // Need to add the column definitions and mappings. AddSchemaTableRows(); if (this._columnMappings.Count == 0) { throw new InvalidOperationException("AddSchemaTableRows did not add rows."); } Debug.Assert(this._schemaTable.Rows.Count == FieldCount); } return new ReadOnlyCollection(_columnMappings); } } /// /// The name of the input row set's schema. /// /// /// This may be different from the target schema but usually they are identical. /// protected abstract string SchemaName { get; } /// /// The name of the input row set's table. /// /// /// This may be different from the target table but usually they are identical. /// protected abstract string TableName { get; } /// /// Adds the input row set's schema to the object. /// /// /// Call /// to do this for each row. /// /// protected abstract void AddSchemaTableRows(); /// /// For each , the optional columns that may have values. /// /// /// This is used for checking the parameters of . /// /// private static readonly Dictionary> AllowedOptionalColumnCombinations = new Dictionary> { { SqlDbType.BigInt, new List { } }, { SqlDbType.Binary, new List { SchemaTableColumn.ColumnSize } }, { SqlDbType.Bit, new List { } }, { SqlDbType.Char, new List { SchemaTableColumn.ColumnSize } }, { SqlDbType.Date, new List { } }, { SqlDbType.DateTime, new List { } }, { SqlDbType.DateTime2, new List { SchemaTableColumn.NumericPrecision } }, { SqlDbType.DateTimeOffset, new List { SchemaTableColumn.NumericPrecision } }, { SqlDbType.Decimal, new List { SchemaTableColumn.NumericPrecision, SchemaTableColumn.NumericScale } }, { SqlDbType.Float, new List { SchemaTableColumn.NumericPrecision, SchemaTableColumn.NumericScale } }, { SqlDbType.Image, new List { } }, { SqlDbType.Int, new List { } }, { SqlDbType.Money, new List { } }, { SqlDbType.NChar, new List { SchemaTableColumn.ColumnSize } }, { SqlDbType.NText, new List { } }, { SqlDbType.NVarChar, new List { SchemaTableColumn.ColumnSize } }, { SqlDbType.Real, new List { } }, { SqlDbType.SmallDateTime, new List { } }, { SqlDbType.SmallInt, new List { } }, { SqlDbType.SmallMoney, new List { } }, { SqlDbType.Structured, new List { } }, { SqlDbType.Text, new List { } }, { SqlDbType.Time, new List { SchemaTableColumn.NumericPrecision } }, { SqlDbType.Timestamp, new List { } }, { SqlDbType.TinyInt, new List { } }, { SqlDbType.Udt, new List { BulkDataReader.DataTypeNameSchemaColumn } }, { SqlDbType.UniqueIdentifier, new List { } }, { SqlDbType.VarBinary, new List { SchemaTableColumn.ColumnSize } }, { SqlDbType.VarChar, new List { SchemaTableColumn.ColumnSize } }, { SqlDbType.Variant, new List { } }, { SqlDbType.Xml, new List { BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, BulkDataReader.XmlSchemaCollectionNameSchemaColumn } } }; /// /// A helper method to support . /// /// /// This methods does extensive argument checks. These errors will cause hard to diagnose exceptions in latter /// processing so it is important to detect them when they can be easily associated with the code defect. /// /// /// The combination of values for the parameters is not supported. /// /// /// A null value for the parameter is not supported. /// /// /// The name of the column. /// /// /// The size of the column which may be null if not applicable. /// /// /// The precision of the column which may be null if not applicable. /// /// /// The scale of the column which may be null if not applicable. /// /// /// Are the column values unique (i.e. never duplicated)? /// /// /// Is the column part of the primary key? /// /// /// Is the column nullable (i.e. optional)? /// /// /// The corresponding . /// /// /// The schema name of the UDT. /// /// /// The type name of the UDT. /// /// /// For XML columns the schema collection's database name. Otherwise, null. /// /// /// For XML columns the schema collection's schema name. Otherwise, null. /// /// /// For XML columns the schema collection's name. Otherwise, null. /// /// protected void AddSchemaTableRow(string columnName, int? columnSize, short? numericPrecision, short? numericScale, bool isUnique, bool isKey, bool allowDbNull, SqlDbType providerType, string udtSchema, string udtType, string xmlSchemaCollectionDatabase, string xmlSchemaCollectionOwningSchema, string xmlSchemaCollectionName) { if (string.IsNullOrEmpty(columnName)) { throw new ArgumentException("columnName must be a nonempty string."); } else if (columnSize.HasValue && columnSize.Value <= 0) { throw new ArgumentOutOfRangeException("columnSize"); } else if (numericPrecision.HasValue && numericPrecision.Value <= 0) { throw new ArgumentOutOfRangeException("numericPrecision"); } else if (numericScale.HasValue && numericScale.Value < 0) { throw new ArgumentOutOfRangeException("columnSize"); } List allowedOptionalColumnList; if (BulkDataReader.AllowedOptionalColumnCombinations.TryGetValue(providerType, out allowedOptionalColumnList)) { if ((columnSize.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.ColumnSize)) || (numericPrecision.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.NumericPrecision)) || (numericScale.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.NumericScale)) || (udtSchema != null && !allowedOptionalColumnList.Contains(BulkDataReader.DataTypeNameSchemaColumn)) || (udtType != null && !allowedOptionalColumnList.Contains(BulkDataReader.DataTypeNameSchemaColumn)) || (xmlSchemaCollectionDatabase != null && !allowedOptionalColumnList.Contains(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn)) || (xmlSchemaCollectionOwningSchema != null && !allowedOptionalColumnList.Contains(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn)) || (xmlSchemaCollectionName != null && !allowedOptionalColumnList.Contains(BulkDataReader.XmlSchemaCollectionNameSchemaColumn))) { throw new ArgumentException("Columns are set that are incompatible with the value of providerType."); } } else { throw new ArgumentException("providerType is unsupported."); } Type dataType; // Corresponding CLR type. string dataTypeName; // Corresponding SQL Server type. bool isLong = false; // Is the column a large value column (e.g. nvarchar(max))? switch (providerType) { case SqlDbType.BigInt: dataType = typeof(long); dataTypeName = "bigint"; break; case SqlDbType.Binary: dataType = typeof(byte[]); if (!columnSize.HasValue) { throw new ArgumentException("columnSize must be specified for \"binary\" type columns."); } else if (columnSize > 8000) { throw new ArgumentOutOfRangeException("columnSize"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "binary({0})", columnSize.Value); break; case SqlDbType.Bit: dataType = typeof(bool); dataTypeName = "bit"; break; case SqlDbType.Char: dataType = typeof(string); if (!columnSize.HasValue) { throw new ArgumentException("columnSize must be specified for \"char\" type columns."); } else if (columnSize > 8000) { throw new ArgumentOutOfRangeException("columnSize"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "char({0})", columnSize.Value); break; case SqlDbType.Date: dataType = typeof(DateTime); dataTypeName = "date"; break; case SqlDbType.DateTime: dataType = typeof(DateTime); dataTypeName = "datetime"; break; case SqlDbType.DateTime2: dataType = typeof(DateTime); if (numericPrecision.HasValue) { if (numericPrecision.Value > 7) { throw new ArgumentOutOfRangeException("numericPrecision"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "datetime2({0})", numericPrecision.Value); } else { dataTypeName = "datetime2"; } break; case SqlDbType.DateTimeOffset: dataType = typeof(DateTimeOffset); if (numericPrecision.HasValue) { if (numericPrecision.Value > 7) { throw new ArgumentOutOfRangeException("numericPrecision"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "datetimeoffset({0})", numericPrecision.Value); } else { dataTypeName = "datetimeoffset"; } break; case SqlDbType.Decimal: dataType = typeof(decimal); if (!numericPrecision.HasValue || !numericScale.HasValue) { throw new ArgumentException("numericPrecision and numericScale must be specified for \"decimal\" type columns."); } else if (numericPrecision > 38) { throw new ArgumentOutOfRangeException("numericPrecision"); } else if (numericScale.Value > numericPrecision.Value) { throw new ArgumentException("numericScale must not be larger than numericPrecision for \"decimal\" type columns."); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "decimal({0}, {1})", numericPrecision.Value, numericScale.Value); break; case SqlDbType.Float: dataType = typeof(double); if (!numericPrecision.HasValue) { throw new ArgumentException("numericPrecision must be specified for \"float\" type columns"); } else if (numericPrecision > 53) { throw new ArgumentOutOfRangeException("numericPrecision"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "float({0})", numericPrecision.Value); break; case SqlDbType.Image: dataType = typeof(byte[]); dataTypeName = "image"; break; case SqlDbType.Int: dataType = typeof(int); dataTypeName = "int"; break; case SqlDbType.Money: dataType = typeof(decimal); dataTypeName = "money"; break; case SqlDbType.NChar: dataType = typeof(string); if (!columnSize.HasValue) { throw new ArgumentException("columnSize must be specified for \"nchar\" type columns"); } else if (columnSize > 4000) { throw new ArgumentOutOfRangeException("columnSize"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "nchar({0})", columnSize.Value); break; case SqlDbType.NText: dataType = typeof(string); dataTypeName = "ntext"; break; case SqlDbType.NVarChar: dataType = typeof(string); if (columnSize.HasValue) { if (columnSize > 4000) { throw new ArgumentOutOfRangeException("columnSize"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "nvarchar({0})", columnSize.Value); } else { isLong = true; dataTypeName = "nvarchar(max)"; } break; case SqlDbType.Real: dataType = typeof(float); dataTypeName = "real"; break; case SqlDbType.SmallDateTime: dataType = typeof(DateTime); dataTypeName = "smalldatetime"; break; case SqlDbType.SmallInt: dataType = typeof(short); dataTypeName = "smallint"; break; case SqlDbType.SmallMoney: dataType = typeof(decimal); dataTypeName = "smallmoney"; break; // SqlDbType.Structured not supported because it related to nested rowsets. case SqlDbType.Text: dataType = typeof(string); dataTypeName = "text"; break; case SqlDbType.Time: dataType = typeof(TimeSpan); if (numericPrecision.HasValue) { if (numericPrecision > 7) { throw new ArgumentOutOfRangeException("numericPrecision"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "time({0})", numericPrecision.Value); } else { dataTypeName = "time"; } break; // SqlDbType.Timestamp not supported because rowversions are not settable. case SqlDbType.TinyInt: dataType = typeof(byte); dataTypeName = "tinyint"; break; case SqlDbType.Udt: if (string.IsNullOrEmpty(udtSchema)) { throw new ArgumentException("udtSchema must be nonnull and nonempty for \"UDT\" columns."); } else if (string.IsNullOrEmpty(udtType)) { throw new ArgumentException("udtType must be nonnull and nonempty for \"UDT\" columns."); } dataType = typeof(object); using (SqlCommandBuilder commandBuilder = new SqlCommandBuilder()) { dataTypeName = commandBuilder.QuoteIdentifier(udtSchema) + "." + commandBuilder.QuoteIdentifier(udtType); } break; case SqlDbType.UniqueIdentifier: dataType = typeof(Guid); dataTypeName = "uniqueidentifier"; break; case SqlDbType.VarBinary: dataType = typeof(byte[]); if (columnSize.HasValue) { if (columnSize > 8000) { throw new ArgumentOutOfRangeException("columnSize"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "varbinary({0})", columnSize.Value); } else { isLong = true; dataTypeName = "varbinary(max)"; } break; case SqlDbType.VarChar: dataType = typeof(string); if (columnSize.HasValue) { if (columnSize > 8000) { throw new ArgumentOutOfRangeException("columnSize"); } dataTypeName = string.Format(CultureInfo.InvariantCulture, "varchar({0})", columnSize.Value); } else { isLong = true; dataTypeName = "varchar(max)"; } break; case SqlDbType.Variant: dataType = typeof(object); dataTypeName = "sql_variant"; break; case SqlDbType.Xml: dataType = typeof(string); if (xmlSchemaCollectionName == null) { if (xmlSchemaCollectionDatabase != null || xmlSchemaCollectionOwningSchema != null) { throw new ArgumentException("xmlSchemaCollectionDatabase and xmlSchemaCollectionOwningSchema must be null if xmlSchemaCollectionName is null for \"xml\" columns."); } dataTypeName = "xml"; } else { if (xmlSchemaCollectionName.Length == 0) { throw new ArgumentException("xmlSchemaCollectionName must be nonempty or null for \"xml\" columns."); } else if (xmlSchemaCollectionDatabase != null && xmlSchemaCollectionDatabase.Length == 0) { throw new ArgumentException("xmlSchemaCollectionDatabase must be null or nonempty for \"xml\" columns."); } else if (xmlSchemaCollectionOwningSchema != null && xmlSchemaCollectionOwningSchema.Length == 0) { throw new ArgumentException("xmlSchemaCollectionOwningSchema must be null or nonempty for \"xml\" columns."); } System.Text.StringBuilder schemaCollection = new System.Text.StringBuilder("xml("); if (xmlSchemaCollectionDatabase != null) { schemaCollection.Append("[" + xmlSchemaCollectionDatabase + "]"); } schemaCollection.Append("[" + (xmlSchemaCollectionOwningSchema == null ? SchemaName : xmlSchemaCollectionOwningSchema) + "]"); schemaCollection.Append("[" + xmlSchemaCollectionName + "]"); dataTypeName = schemaCollection.ToString(); } break; default: throw new ArgumentOutOfRangeException("providerType"); } this._schemaTable.Rows.Add(columnName, _schemaTable.Rows.Count, columnSize, numericPrecision, numericScale, isUnique, isKey, "TraceServer", "TraceWarehouse", columnName, SchemaName, TableName, dataType, allowDbNull, providerType, false, // isAliased false, // isExpression false, // isIdentity, false, // isAutoIncrement, false, // isRowVersion, false, // isHidden, isLong, true, // isReadOnly, dataType, dataTypeName, xmlSchemaCollectionDatabase, xmlSchemaCollectionOwningSchema, xmlSchemaCollectionName); this._columnMappings.Add(new SqlBulkCopyColumnMapping(columnName, columnName)); } #endregion #region Constructors private const string IsIdentitySchemaColumn = "IsIdentity"; private const string DataTypeNameSchemaColumn = "DataTypeName"; private const string XmlSchemaCollectionDatabaseSchemaColumn = "XmlSchemaCollectionDatabase"; private const string XmlSchemaCollectionOwningSchemaSchemaColumn = "XmlSchemaCollectionOwningSchema"; private const string XmlSchemaCollectionNameSchemaColumn = "XmlSchemaCollectionName"; /// /// Constructor. /// protected BulkDataReader() { this._schemaTable.Locale = System.Globalization.CultureInfo.InvariantCulture; DataColumnCollection columns = _schemaTable.Columns; columns.Add(SchemaTableColumn.ColumnName, typeof(string)); columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int)); columns.Add(SchemaTableColumn.ColumnSize, typeof(int)); columns.Add(SchemaTableColumn.NumericPrecision, typeof(short)); columns.Add(SchemaTableColumn.NumericScale, typeof(short)); columns.Add(SchemaTableColumn.IsUnique, typeof(bool)); columns.Add(SchemaTableColumn.IsKey, typeof(bool)); columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string)); columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string)); columns.Add(SchemaTableColumn.BaseColumnName, typeof(string)); columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string)); columns.Add(SchemaTableColumn.BaseTableName, typeof(string)); columns.Add(SchemaTableColumn.DataType, typeof(Type)); columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool)); columns.Add(SchemaTableColumn.ProviderType, typeof(int)); columns.Add(SchemaTableColumn.IsAliased, typeof(bool)); columns.Add(SchemaTableColumn.IsExpression, typeof(bool)); columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(bool)); columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool)); columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool)); columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool)); columns.Add(SchemaTableColumn.IsLong, typeof(bool)); columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool)); columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type)); columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(string)); columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(string)); columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(string)); columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(string)); } #endregion #region IDataReader /// /// Gets a value indicating the depth of nesting for the current row. (Inherited from .) /// /// /// does not support nested result sets so this method always returns 0. /// /// public int Depth { get { return 0; } } /// /// Gets the number of columns in the current row. (Inherited from .) /// /// public int FieldCount { get { return GetSchemaTable().Rows.Count; } } /// /// Is the bulk copy process open? /// bool _isOpen = true; /// /// Gets a value indicating whether the data reader is closed. (Inherited from .) /// /// public bool IsClosed { get { return !_isOpen; } } /// /// Gets the column located at the specified index. (Inherited from .) /// /// /// No column with the specified index was found. /// /// /// The zero-based index of the column to get. /// /// /// The column located at the specified index as an . /// /// public object this[int i] { get { return GetValue(i); } } /// /// Gets the column with the specified name. (Inherited from .) /// /// /// No column with the specified name was found. /// /// /// The name of the column to find. /// /// /// The column located at the specified name as an . /// /// public object this[string name] { get { return GetValue(GetOrdinal(name)); } } /// /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. (Inherited from .) /// /// /// Always returns -1 which is the expected behaviour for statements. /// /// public virtual int RecordsAffected { get { return -1; } } /// /// Closes the . (Inherited from .) /// /// public void Close() { this._isOpen = false; } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public bool GetBoolean(int i) { return (bool)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public byte GetByte(int i) { return (byte)GetValue(i); } /// /// Reads a stream of bytes from the specified column offset into the buffer as an array, starting at the given buffer offset. /// (Inherited from .) /// /// /// If you pass a buffer that is null, returns the length of the row in bytes. /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The index within the field from which to start the read operation. /// /// /// The buffer into which to read the stream of bytes. /// /// /// The index for buffer to start the read operation. /// /// /// The number of bytes to read. /// /// /// The actual number of bytes read. /// /// public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { byte[] data = (byte[])GetValue(i); if (buffer != null) { Array.Copy(data, fieldOffset, buffer, bufferoffset, length); } return data.LongLength; } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public char GetChar(int i) { char result; object data = GetValue(i); char? dataAsChar = data as char?; char[] dataAsCharArray = data as char[]; string dataAsString = data as string; if (dataAsChar.HasValue) { result = dataAsChar.Value; } else if (dataAsCharArray != null && dataAsCharArray.Length == 1) { result = dataAsCharArray[0]; } else if (dataAsString != null && dataAsString.Length == 1) { result = dataAsString[0]; } else { throw new InvalidOperationException("GetValue did not return a Char compatible type."); } return result; } /// /// Reads a stream of characters from the specified column offset into the buffer as an array, starting at the given buffer offset. /// (Inherited from .) /// /// /// If you pass a buffer that is null, returns the length of the row in bytes. /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The index within the field from which to start the read operation. /// /// /// The buffer into which to read the stream of characters. /// /// /// The index for buffer to start the read operation. /// /// /// The number of characters to read. /// /// /// The actual number of characters read. /// /// public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) { object data = GetValue(i); string dataAsString = data as string; char[] dataAsCharArray = data as char[]; if (dataAsString != null) { dataAsCharArray = dataAsString.ToCharArray((int)fieldoffset, length); } else if (dataAsCharArray == null) { throw new InvalidOperationException("GetValue did not return either a Char array or a String."); } if (buffer != null) { Array.Copy(dataAsCharArray, fieldoffset, buffer, bufferoffset, length); } return dataAsCharArray.LongLength; } /// /// Returns an IDataReader for the specified column ordinal. (Inherited from .) /// /// /// does not support nested result sets so this method always returns null. /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The for the specified column ordinal (null). /// /// public IDataReader GetData(int i) { if (i < 0 || i >= this.FieldCount) { throw new ArgumentOutOfRangeException("i"); } return null; } /// /// The data type information for the specified field. (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The data type information for the specified field. /// /// public string GetDataTypeName(int i) { return GetFieldType(i).Name; } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public DateTime GetDateTime(int i) { return (DateTime)GetValue(i); } /// /// Gets the value of the specified column as a . /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// public DateTimeOffset GetDateTimeOffset(int i) { return (DateTimeOffset)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public decimal GetDecimal(int i) { return (decimal)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public double GetDouble(int i) { return (double)GetValue(i); } /// /// Gets the information corresponding to the type of that would be returned from . /// (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The information corresponding to the type of that would be returned from . /// /// public Type GetFieldType(int i) { return (Type)GetSchemaTable().Rows[i][SchemaTableColumn.DataType]; } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public float GetFloat(int i) { return (float)this[i]; } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public Guid GetGuid(int i) { return (Guid)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public short GetInt16(int i) { return (short)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public int GetInt32(int i) { return (int)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public long GetInt64(int i) { return (long)GetValue(i); } /// /// Gets the name for the field to find. (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The name of the field or the empty string (""), if there is no value to return. /// /// public string GetName(int i) { return (string)GetSchemaTable().Rows[i][SchemaTableColumn.ColumnName]; } /// /// Return the index of the named field. (Inherited from .) /// /// /// The index of the named field was not found. /// /// /// The name of the field to find. /// /// /// The index of the named field. /// /// public int GetOrdinal(string name) { if (name == null) // Empty strings are handled as a IndexOutOfRangeException. { throw new ArgumentNullException("name"); } int result = -1; int rowCount = FieldCount; DataRowCollection schemaRows = GetSchemaTable().Rows; // Case sensitive search for (int ordinal = 0; ordinal < rowCount; ordinal++) { if (String.Equals((string)schemaRows[ordinal][SchemaTableColumn.ColumnName], name, StringComparison.Ordinal)) { result = ordinal; } } if (result == -1) { // Case insensitive search. for (int ordinal = 0; ordinal < rowCount; ordinal++) { if (String.Equals((string)schemaRows[ordinal][SchemaTableColumn.ColumnName], name, StringComparison.OrdinalIgnoreCase)) { result = ordinal; } } } if (result == -1) { throw new IndexOutOfRangeException(name); } return result; } /// /// Returns a that describes the column metadata of the . (Inherited from .) /// /// /// The is closed. /// /// /// A that describes the column metadata. /// /// public DataTable GetSchemaTable() { if (IsClosed) { throw new InvalidOperationException("The IDataReader is closed."); } if (_schemaTable.Rows.Count == 0) { // Need to add the column definitions and mappings _schemaTable.TableName = TableName; AddSchemaTableRows(); Debug.Assert(_schemaTable.Rows.Count == FieldCount); } return _schemaTable; } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public string GetString(int i) { return (string)GetValue(i); } /// /// Gets the value of the specified column as a . /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// public TimeSpan GetTimeSpan(int i) { return (TimeSpan)GetValue(i); } /// /// Gets the value of the specified column as a . (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// The value of the column. /// /// public abstract object GetValue(int i); /// /// Populates an array of objects with the column values of the current record. (Inherited from .) /// /// /// was null. /// /// /// An array of to copy the attribute fields into. /// /// /// The number of instances of in the array. /// /// public int GetValues(object[] values) { if (values == null) { throw new ArgumentNullException("values"); } int fieldCount = Math.Min(FieldCount, values.Length); for (int i = 0; i < fieldCount; i++) { values[i] = GetValue(i); } return fieldCount; } /// /// Return whether the specified field is set to null. (Inherited from .) /// /// /// The index passed was outside the range of 0 through . /// /// /// The zero-based column ordinal. /// /// /// True if the specified field is set to null; otherwise, false. /// /// public bool IsDBNull(int i) { object data = GetValue(i); return data == null || Convert.IsDBNull(data); } /// /// Advances the data reader to the next result, when reading the results of batch SQL statements. (Inherited from .) /// /// /// for returns a single result set so false is always returned. /// /// /// True if there are more rows; otherwise, false. for returns a single result set so false is always returned. /// /// public bool NextResult() { return false; } /// /// Advances the to the next record. (Inherited from .) /// /// /// True if there are more rows; otherwise, false. /// /// public abstract bool Read(); #endregion #region IDisposable /// /// Has the object been disposed? /// bool _disposed = false; /// /// Dispose of any disposable and expensive resources. /// /// /// Is this call the result of a call? /// protected virtual void Dispose(bool disposing) { if (!this._disposed) { this._disposed = true; if (disposing) { if (_schemaTable != null) { _schemaTable.Dispose(); this._schemaTable = null; } this._columnMappings = null; this._isOpen = false; GC.SuppressFinalize(this); } } } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. (Inherited from .) /// /// public void Dispose() { Dispose(true); } /// /// Finalizer /// /// /// has no unmanaged resources but a subclass may thus a finalizer is required. /// ~BulkDataReader() { Dispose(false); } #endregion } }