/// <summary> /// <para>Creates an <see cref="IDbJob{List{object}}"/> able to execute a reader based on the configured parameters.</para> /// <para>Valid types: <see cref="DataSet"/>, <see cref="DataTable"/>, <see cref="Dictionary{string,object}"/>, any .NET built-in type, or any struct or class with a parameterless constructor not assignable from <see cref="System.Collections.IEnumerable"/> (Note: only properties will be mapped).</para> /// See also: /// <seealso cref="DbCommand.ExecuteReader()"/> /// </summary> /// <remarks> /// This will use the <see cref="CommandBehavior.SingleResult"/> behavior by default. /// </remarks> /// <param name="type">The <see cref="Type"/> to use.</param> /// <param name="mapSettings">The <see cref="IColumnMapSetting"/> to use.</param> /// <param name="sql">The query text command to run against the data source.</param> /// <param name="param">The parameter to use. <see cref="DbJobParameterCollection.AddFor(object, bool, string, string)"/> restrictions apply. (Optional)</param> /// <param name="commandType">The <see cref="CommandType"/> to use. (Optional)</param> /// <param name="commandBehavior">The <see cref="CommandBehavior"/> to use. (Optional)</param> /// <param name="commandTimeout">The time in seconds to wait for the command to execute. (Optional)</param> /// <param name="flags">The flags to use. (Optional)</param> /// <returns>The <see cref="IDbJob{List{object}}"/>.</returns> public IDbJob <List <object> > ReadToList( Type type, IColumnMapSetting mapSettings, string sql, object param = null, CommandType commandType = CommandType.Text, CommandBehavior?commandBehavior = null, int?commandTimeout = null, DbJobCommandFlags flags = DbJobCommandFlags.None) { if (type == null) { throw new ArgumentNullException("type cannot be null!"); } return(new DbJob <List <object>, TDbConnection> ( setting: _jobSetting, state: new DbConnectorSimpleState { Flags = _flags }, onCommands: (conn, state) => BuildJobCommandForSimpleState(conn, state, mapSettings, sql, param, commandType, commandBehavior, commandTimeout, flags), onExecute: (d, p) => OnExecuteReadToList(type, p) ).SetOnError((d, e) => new List <object>())); }
/// <summary> /// <para>Creates an <see cref="IDbJob{object}"/> able to execute a reader based on the configured parameters.</para> /// <para>Use this to load only a single row from the query result into an object.</para> /// <para>Valid types: <see cref="DataSet"/>, <see cref="DataTable"/>, <see cref="Dictionary{string,object}"/>, any .NET built-in type, or any struct or class with a parameterless constructor not assignable from <see cref="System.Collections.IEnumerable"/> (Note: only properties will be mapped).</para> /// See also: /// <seealso cref="DbCommand.ExecuteReader()"/> /// </summary> /// <remarks> /// This will use the <see cref="CommandBehavior.SingleResult"/> behavior by default. /// </remarks> /// <param name="type">The <see cref="Type"/> to use.</param> /// <param name="mapSettings">The <see cref="IColumnMapSetting"/> to use.</param> /// <param name="sql">The query text command to run against the data source.</param> /// <param name="param">The parameter to use. <see cref="DbJobParameterCollection.AddFor(object, bool, string, string)"/> restrictions apply. (Optional)</param> /// <param name="commandType">The <see cref="CommandType"/> to use. (Optional)</param> /// <param name="commandBehavior">The <see cref="CommandBehavior"/> to use. (Optional)</param> /// <param name="commandTimeout">The time in seconds to wait for the command to execute. (Optional)</param> /// <param name="flags">The flags to use. (Optional)</param> /// <returns>The <see cref="IDbJob{object}"/>.</returns> /// <exception cref="InvalidOperationException">The query result has more than one result.</exception> public IDbJob <object> ReadSingleOrDefault( Type type, IColumnMapSetting mapSettings, string sql, object param = null, CommandType commandType = CommandType.Text, CommandBehavior?commandBehavior = null, int?commandTimeout = null, DbJobCommandFlags flags = DbJobCommandFlags.None) { if (type == null) { throw new ArgumentNullException("type cannot be null!"); } return(new DbJob <object, TDbConnection> ( setting: _jobSetting, state: new DbConnectorSimpleState { Flags = _flags }, onInit: () => type.IsValueType ? Activator.CreateInstance(type) : null, onCommands: (conn, state) => BuildJobCommandForSimpleState(conn, state, mapSettings, sql, param, commandType, commandBehavior, commandTimeout, flags), onExecute: (d, p) => OnExecuteReadSingleOrDefault(type, p) )); }
/// <summary> /// <para>Creates an <see cref="IDbJob{IEnumerable{dynamic}}"/> able to execute a reader based on the configured parameters.</para> /// <para>Use this to dynamically load the query results into an IEnumerable of <see cref="System.Dynamic.ExpandoObject"/>.</para> /// See also: /// <seealso cref="DbCommand.ExecuteReader()"/> /// </summary> /// <remarks> /// This will use the <see cref="CommandBehavior.SingleResult"/> behavior by default. /// </remarks> /// <param name="mapSettings">The <see cref="IColumnMapSetting"/> to use.</param> /// <param name="sql">The query text command to run against the data source.</param> /// <param name="param">The parameter to use. <see cref="DbJobParameterCollection.AddFor(object, bool, string, string)"/> restrictions apply. (Optional)</param> /// <param name="commandType">The <see cref="CommandType"/> to use. (Optional)</param> /// <param name="commandBehavior">The <see cref="CommandBehavior"/> to use. (Optional)</param> /// <param name="commandTimeout">The time in seconds to wait for the command to execute. (Optional)</param> /// <param name="flags">The flags to use. (Optional)</param> /// <returns>The <see cref="IDbJob{IEnumerable{dynamic}}"/>.</returns> public IDbJob <IEnumerable <dynamic> > Read( IColumnMapSetting mapSettings, string sql, object param = null, CommandType commandType = CommandType.Text, CommandBehavior?commandBehavior = null, int?commandTimeout = null, DbJobCommandFlags flags = DbJobCommandFlags.None) { return(new DbJob <IEnumerable <dynamic>, TDbConnection> ( setting: _jobSetting, state: new DbConnectorSimpleState { Flags = _flags }, onCommands: (conn, state) => BuildJobCommandForSimpleState(conn, state, mapSettings, sql, param, commandType, commandBehavior, commandTimeout, flags), onExecute: (d, p) => OnExecuteReadDynamic(d, p) ).SetOnError((d, e) => Enumerable.Empty <dynamic>())); }
/// <summary> /// <para>Creates an <see cref="IDbJob{dynamic}"/> able to execute a reader based on the configured parameters.</para> /// <para>Use this to dynamically load only a single row from the query result into a <see cref="System.Dynamic.ExpandoObject"/>.</para> /// See also: /// <seealso cref="DbCommand.ExecuteReader()"/> /// </summary> /// <remarks> /// This will use the <see cref="CommandBehavior.SingleResult"/> behavior by default. /// </remarks> /// <param name="mapSettings">The <see cref="IColumnMapSetting"/> to use.</param> /// <param name="sql">The query text command to run against the data source.</param> /// <param name="param">The parameter to use. <see cref="DbJobParameterCollection.AddFor(object, bool, string, string)"/> restrictions apply. (Optional)</param> /// <param name="commandType">The <see cref="CommandType"/> to use. (Optional)</param> /// <param name="commandBehavior">The <see cref="CommandBehavior"/> to use. (Optional)</param> /// <param name="commandTimeout">The time in seconds to wait for the command to execute. (Optional)</param> /// <param name="flags">The flags to use. (Optional)</param> /// <returns>The <see cref="IDbJob{dynamic}"/>.</returns> /// <exception cref="InvalidOperationException">The query result has more than one result.</exception> public IDbJob <dynamic> ReadSingleOrDefault( IColumnMapSetting mapSettings, string sql, object param = null, CommandType commandType = CommandType.Text, CommandBehavior?commandBehavior = null, int?commandTimeout = null, DbJobCommandFlags flags = DbJobCommandFlags.None) { return(new DbJob <dynamic, TDbConnection> ( setting: _jobSetting, state: new DbConnectorSimpleState { Flags = _flags }, onCommands: (conn, state) => BuildJobCommandForSimpleState(conn, state, mapSettings, sql, param, commandType, commandBehavior, commandTimeout, flags), onExecute: (d, p) => OnExecuteReadSingleOrDefaultDynamic(d, p) )); }
/// <summary> /// <para>Creates an <see cref="IDbJob{object}"/> to get the first column of the first row in the result /// set returned by the query. All other columns and rows are ignored.</para> /// See also: /// <seealso cref="DbCommand.ExecuteScalar"/> /// </summary> /// <param name="mapSettings">The <see cref="IColumnMapSetting"/> to use.</param> /// <param name="sql">The query text command to run against the data source.</param> /// <param name="param">The parameter to use. <see cref="DbJobParameterCollection.AddFor(object, bool, string, string)"/> restrictions apply. (Optional)</param> /// <param name="commandType">The <see cref="CommandType"/> to use. (Optional)</param> /// <param name="commandBehavior">The <see cref="CommandBehavior"/> to use. (Optional)</param> /// <param name="commandTimeout">The time in seconds to wait for the command to execute. (Optional)</param> /// <param name="flags">The flags to use. (Optional)</param> /// <returns>The <see cref="IDbJob{object}"/>.</returns> public IDbJob <object> Scalar( IColumnMapSetting mapSettings, string sql, object param = null, CommandType commandType = CommandType.Text, CommandBehavior?commandBehavior = null, int?commandTimeout = null, DbJobCommandFlags flags = DbJobCommandFlags.None) { return(new DbJob <object, TDbConnection> ( setting: _jobSetting, state: new DbConnectorSimpleState { Flags = _flags }, onCommands: (conn, state) => BuildJobCommandForSimpleState(conn, state, mapSettings, sql, param, commandType, commandBehavior, commandTimeout, flags), onExecute: (d, p) => { object scalar = p.Command.ExecuteScalar(); return scalar != DBNull.Value ? scalar : null; } )); }
/// <summary> /// Creates an <see cref="IEnumerable{ColumnMap}"/> based on the provided type. /// </summary> /// <param name="odr">The <see cref="DbDataReader"/> to use.</param> /// <param name="objType">The <see cref="Type"/> to use.</param> /// <param name="settings">The <see cref="IColumnMapSetting"/> to use. (Optional)</param> /// <returns>The <see cref="IEnumerable{ColumnMap}"/>.</returns> public static IEnumerable <ColumnMap> GetColumnMaps(this DbDataReader odr, Type objType, IColumnMapSetting settings = null) { return(DbConnectorUtilities.GetColumnMaps(objType, odr.GetOrdinalColumnNames(settings), settings)); }
internal static OrdinalColumnMapLite[] GetOrdinalColumnNamesLite(this DbDataReader odr, IColumnMapSetting settings = null) { if (settings == null || (!settings.HasNamesToInclude && !settings.HasNamesToExclude)) { var ordinalColumnMap = new OrdinalColumnMapLite[odr.FieldCount]; for (int i = 0; i < odr.FieldCount; i++) { ordinalColumnMap[i] = new OrdinalColumnMapLite { Ordinal = i, Name = odr.GetName(i) }; } return(ordinalColumnMap); } else { bool hasNamesToInclude = settings.HasNamesToInclude; bool hasNamesToExclude = settings.HasNamesToExclude; var tempMap = new Queue <OrdinalColumnMapLite>(odr.FieldCount); for (int i = 0; i < odr.FieldCount; i++) { string colName = odr.GetName(i); if (!DbConnectorUtilities.IsColumnNameExcluded(colName, hasNamesToInclude, hasNamesToExclude, settings)) { tempMap.Enqueue(new OrdinalColumnMapLite { Ordinal = i, Name = colName }); } } if (tempMap.Count > 0) { var ordinalColumnMap = new OrdinalColumnMapLite[tempMap.Count]; for (int i = 0; tempMap.Count > 0; i++) { ordinalColumnMap[i] = tempMap.Dequeue(); } return(ordinalColumnMap); } else { return(null); } } }
/// <summary> /// Reads data into a <see cref="DataSet"/>. /// </summary> /// <param name="odr">The <see cref="DataSet"/> to use.</param> /// <param name="isFirstResult">Set to true if only the first item result should be loaded.</param> /// <param name="token">The <see cref="CancellationToken"/> to use. (Optional)</param> /// <param name="settings">The <see cref="IColumnMapSetting"/> to use. (Optional)</param> /// <returns>The <see cref="DataSet"/>.</returns> public static DataSet ToDataSet(this DbDataReader odr, bool isFirstResult, CancellationToken token, IColumnMapSetting settings, DataSet projectedDataSet = null) { projectedDataSet = projectedDataSet ?? new DataSet(); bool hasNext = true; while ((hasNext && odr.HasRows) || odr.NextResult()) { if (token.IsCancellationRequested) { return(projectedDataSet); } projectedDataSet.Tables.Add(odr.ToDataTable(isFirstResult, token, settings)); hasNext = odr.NextResult(); } return(projectedDataSet); }
/// <summary> /// Reads data into a <see cref="DataTable"/>. /// </summary> /// <param name="odr">The <see cref="DbDataReader"/> to use.</param> /// <param name="isFirstResult">Set to true if only the first row should be loaded.</param> /// <param name="token">The <see cref="CancellationToken"/> to use. (Optional)</param> /// <param name="settings">The <see cref="IColumnMapSetting"/> to use. (Optional)</param> /// <returns>The <see cref="DataTable"/>.</returns> public static DataTable ToDataTable(this DbDataReader odr, bool isFirstResult, CancellationToken token, IColumnMapSetting settings) { var dt = new DataTable(); if (odr.HasRows) { if (isFirstResult || (settings != null && (settings.HasNamesToInclude || settings.HasNamesToExclude))) { var ordinalColumnMap = odr.GetOrdinalColumnNamesLite(settings); if (ordinalColumnMap?.Length > 0) { foreach (var m in ordinalColumnMap) { dt.Columns.Add(m.Name); } if (isFirstResult) { if (odr.Read()) { DataRow row = dt.NewRow(); for (int i = 0; i < ordinalColumnMap.Length; i++) { row[i] = odr.GetValue(ordinalColumnMap[i].Ordinal); } dt.Rows.Add(row); } } else { while (odr.Read()) { if (token.IsCancellationRequested) { break; } DataRow row = dt.NewRow(); for (int i = 0; i < ordinalColumnMap.Length; i++) { row[i] = odr.GetValue(ordinalColumnMap[i].Ordinal); } dt.Rows.Add(row); } } } } else { dt.Load(odr); } } return(dt); }
/// <summary> /// Creates an <see cref="IEnumerable{ColumnMap}"/> using the properties of the T type and the keys. /// </summary> /// <param name="ordinalColumnMap">The ordinal column map.</param> /// <param name="settings">The settings to use.</param> /// <returns>A list with the ColumnMap objects.</returns> /// <exception cref="System.InvalidCastException">Thrown when a property of <typeparamref name="T"/> does not match the located key type.</exception> internal static IEnumerable <ColumnMap> GetColumnMaps <T>(OrdinalColumnMap[] ordinalColumnMap, IColumnMapSetting settings) { return(GetColumnMaps(typeof(T), ordinalColumnMap, settings)); }
internal static bool IsColumnNameExcluded(string columnName, bool hasNamesToInclude, bool hasNamesToExclude, IColumnMapSetting settings) { if (hasNamesToInclude && hasNamesToExclude && (!settings.NamesToInclude.Contains(columnName) || settings.NamesToExclude.Contains(columnName))) { return(true); } else if (hasNamesToInclude && !settings.NamesToInclude.Contains(columnName)) { return(true); } else if (hasNamesToExclude && settings.NamesToExclude.Contains(columnName)) { return(true); } return(false); }
internal static int GetJoinStartIndex(Type tType, OrdinalColumnMap[] ordinalColumnMap, IColumnMapSetting settings) { if (settings.Joins.TryGetValue(tType, out string columnName)) { int splitStartIndex = Array.FindIndex(ordinalColumnMap, c => !c.IsMapped && c.Name == columnName); if (splitStartIndex == -1) { return(0); } return(splitStartIndex); } return(0); }
private static IEnumerable <ColumnMap> BuildColumnMaps( Type tType, OrdinalColumnMap[] keys, ColumnMapBuilderState state, IColumnMapSetting settings) { state.ProcessedTypes.Add(tType); PropertyInfo[] props = tType.GetProperties(_bindingFlagInstancePublic); int joinStartIndex = state.HasJoins ? GetJoinStartIndex(tType, keys, settings) : 0; for (int i = 0; i < props.Length; i++) { var p = props[i]; if (state.MappedCount == state.NonExcludedCount) { break; } if (p.CanWrite && p.GetCustomAttribute <NotMappedAttribute>() == null) { Type propertyType = p.PropertyType; Type nullUnderlyingType = Nullable.GetUnderlyingType(propertyType); if ( state.HasJoins && settings.Joins.ContainsKey(propertyType) && !state.ProcessedTypes.Contains(propertyType) && !_directTypeMap.Contains(propertyType) && ((propertyType.IsClass && propertyType.GetConstructor(Type.EmptyTypes) != null) || (propertyType.IsValueType && !(propertyType.IsEnum || (nullUnderlyingType?.IsEnum ?? false)))) && !propertyType.IsArray && !typeof(IEnumerable).IsAssignableFrom(propertyType) && !typeof(IListSource).IsAssignableFrom(propertyType) ) { var childrenMaps = BuildColumnMaps ( propertyType, keys, state, settings ).OrderBy(m => m.Column.Ordinal).ToArray(); if (childrenMaps.Length > 0) { var parentMap = new ColumnParentMap { SetMethod = p.GetSetMethod(false), PropInfo = p, Children = childrenMaps }; yield return(new ColumnMap { Column = childrenMaps[0].Column, ParentMap = parentMap }); } continue; } string propColName = p.GetColumnAttributeName(); if (state.HasAliases && settings.Aliases.TryGetValue(tType, out Dictionary <string, string> aliasMap)) { if (aliasMap != null && aliasMap.TryGetValue(propColName, out string alias)) { propColName = alias; } } var keyIndex = Array.FindIndex(keys, joinStartIndex, c => !c.IsMapped && c.Name == propColName); if (keyIndex >= 0) { var ordinalMap = keys[keyIndex]; Type underlyingType = (nullUnderlyingType ?? propertyType); ThrowIfFailedToMatchColumnTypeByNames(ordinalMap.FieldType, underlyingType, ordinalMap.Name, p.Name); yield return(new ColumnMap { UnderlyingType = underlyingType, SetMethod = p.GetSetMethod(false), PropInfo = p, Column = ordinalMap }); ordinalMap.IsMapped = true; state.MappedCount++; } #if DEBUG else { Debug.WriteLine("Column name " + propColName + " not found in column schema for property " + propertyType + " of object " + tType); } #endif } } }
/// <summary> /// Creates an <see cref="IEnumerable{ColumnMap}"/> using the properties of the tType and the keys. /// </summary> /// <param name="tType">The type to use.</param> /// <param name="ordinalColumnMap">The ordinal column map.</param> /// <param name="settings">The settings to use.</param> /// <returns>A list with the ColumnMap objects.</returns> /// <exception cref="System.InvalidCastException">Thrown when a property of <paramref name="tType"/> does not match the located key type.</exception> internal static IEnumerable <ColumnMap> GetColumnMaps(Type tType, OrdinalColumnMap[] ordinalColumnMap, IColumnMapSetting settings) { if (ordinalColumnMap == null || ordinalColumnMap.Length == 0) { return(Enumerable.Empty <ColumnMap>()); } return(BuildColumnMaps ( tType, ordinalColumnMap, settings == null ? new ColumnMapBuilderState { NonExcludedCount = ordinalColumnMap.Length, ProcessedTypes = new HashSet <Type>() } : new ColumnMapBuilderState { NonExcludedCount = ordinalColumnMap.Length, ProcessedTypes = new HashSet <Type>(), HasJoins = settings.HasJoins, HasAliases = settings.HasAliases, }, settings ).OrderBy(m => m.Column.Ordinal).ToArray()); }
public static T GetMappedObject <T>(this DbDataReader odr, IColumnMapSetting settings = null) { var columnMaps = DbConnectorUtilities.GetColumnMaps(typeof(T), odr.GetOrdinalColumnNames(settings), settings); return(odr.GetMappedObject <T>(columnMaps)); }
public static object GetMappedObject(this DbDataReader odr, Type objType, IColumnMapSetting settings = null) { var columnMaps = DbConnectorUtilities.GetColumnMaps(objType, odr.GetOrdinalColumnNames(settings), settings); return(odr.GetMappedObject(objType, columnMaps)); }
internal static int GetJoinStartIndex(Type tType, OrdinalColumnMap[] ordinalColumnMap, IColumnMapSetting settings) { if (settings.Splits.TryGetValue(tType, out string columnName)) { int splitStartIndex = Array.FindIndex(ordinalColumnMap, c => !c.IsMapped && string.Equals(c.Name, columnName, StringComparison.OrdinalIgnoreCase)); if (splitStartIndex == -1) { return(0); } return(splitStartIndex); } return(0); }