/// <summary> /// Obtiene una cadena SQL con los valores de los parámetros insertados en la propia cadena /// </summary> public string ConvertSqlNoParameters(string sql, ParametersDbCollection inputParametersDb, string parameterPrefix) { string sqlOutput = string.Empty; System.Text.RegularExpressions.Match match = System.Text.RegularExpressions.Regex.Match(sql, "\\" + parameterPrefix + "\\w*", System.Text.RegularExpressions.RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1)); int lastIndex = 0; // Mientras haya una coincidencia while (match.Success) { // Añade lo anterior del SQL a la cadena de salida y cambia el índice de último elemento encontrado sqlOutput += sql.Substring(lastIndex, match.Index - lastIndex); lastIndex = match.Index + match.Length; // Añade el valor del parámetro a la cadena de salida sqlOutput += ConvertToSqlValue(GetParameterValue(parameterPrefix, sql.Substring(match.Index, match.Length), inputParametersDb, 0)); // Pasa a la siguiente coincidencia match = match.NextMatch(); } // Añade el resto de la cadena inicial if (lastIndex < sql.Length) { sqlOutput += sql.Substring(lastIndex); } // Devuelve la colección de parámetros para la base de datos return(sqlOutput); }
/// <summary> /// Obtiene el número de registro de una consulta /// </summary> public async Task <long?> GetRecordsCountAsync(string sql, ParametersDbCollection parametersDB, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { if (SqlParser == null) { return(null); } else { object result = await ExecuteScalarAsync(SqlParser.GetSqlCount(sql), parametersDB, CommandType.Text, timeOut, cancellationToken); if (result == null) { return(null); } else if (result is long) { return((long?)result); } else { return((int?)result); } } }
/// <summary> /// Obtiene el datareader de una consulta /// </summary> internal async Task <DbDataReader> ExecuteReaderAsync(IDbProvider provider, string query, Models.ArgumentListModel arguments, TimeSpan timeout, CancellationToken cancellationToken) { List <SqlSectionModel> scripts = new SqlParser().Tokenize(query, arguments.Constants.ToDictionary(), out string error); if (!string.IsNullOrWhiteSpace(error)) { throw new Exception(error); } else { ParametersDbCollection parametersDb = ConvertParameters(provider, arguments.Parameters); // Obtiene el datareader foreach (SqlSectionModel script in scripts) { if (script.Type == SqlSectionModel.SectionType.Sql) { string sql = provider.SqlHelper.ConvertSqlNoParameters(script.Content, parametersDb).TrimIgnoreNull(); if (!string.IsNullOrWhiteSpace(sql)) { return(await provider.ExecuteReaderAsync(sql, null, CommandType.Text, timeout, cancellationToken)); } } } // Si ha llegado hasta aquí es porque no ha leído nada return(null); } }
/// <summary> /// Carga un objeto utilizando genéricos /// </summary> public TypeData LoadObject(string text, ParametersDbCollection parametersDB, CommandType commandType, AssignDataCallBack callBack) { TypeData data; // Abre la conexión Connection.Open(); // Lee los datos using (IDataReader reader = Connection.ExecuteReader(text, parametersDB, commandType)) { // Lee los datos if (reader.Read()) { data = (TypeData)callBack(reader); } else { data = (TypeData)callBack(null); } // Cierra el recordset reader.Close(); } // Cierra la conexión Connection.Close(); // Devuelve el objeto return(data); }
/// <summary> /// Ejecuta una sentencia o un procedimiento sobre la base de datos de forma asíncrona /// </summary> public async Task <int> ExecuteAsync(string sql, ParametersDbCollection parameters, CommandType commandType, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { int rows; // Ejecuta la consulta using (IDbCommand command = GetCommand(sql, timeOut)) { // Indica el tipo del comando command.CommandType = commandType; command.CommandTimeout = GetTimeout(timeOut); // Añade los parámetros al comando AddParameters(command, parameters); // Ejecuta la consulta rows = await(command as DbCommand).ExecuteNonQueryAsync(cancellationToken ?? CancellationToken.None); // Pasa los valores de salida de los parámetros del comando a la colección de parámetros de entrada if (parameters != null) { parameters.Clear(); parameters.AddRange(ReadOutputParameters(command.Parameters)); } } // Devuelve el número de registros afectados return(rows); }
/// <summary> /// Carga las columnas de la vista /// </summary> private async Task LoadColumnsAsync(SqlServerProvider connection, ViewDbModel view, TimeSpan timeout, CancellationToken cancellationToken) { ParametersDbCollection parameters = new ParametersDbCollection(); string sql = @"SELECT Table_Catalog, Table_Schema, Table_Name, Column_Name FROM Information_Schema.View_Column_Usage WHERE View_Catalog = @View_Catalog AND View_Schema = @View_Schema AND View_Name = @View_Name" ; // Asigna lo parámetros parameters.Add("@View_Catalog", view.Catalog); parameters.Add("@View_Schema", view.Schema); parameters.Add("@View_Name", view.Name); // Carga las columnas using (DbDataReader reader = await connection.ExecuteReaderAsync(sql, parameters, CommandType.Text, timeout, cancellationToken)) { // Lee los registros while (!cancellationToken.IsCancellationRequested && await reader.ReadAsync(cancellationToken)) { FieldDbModel column = new FieldDbModel(); // Carga los datos de la columna column.Catalog = (string)reader.IisNull("Table_Catalog"); column.Schema = (string)reader.IisNull("Table_Schema"); column.Table = (string)reader.IisNull("Table_Name"); column.Name = (string)reader.IisNull("Column_Name"); // Añade la columna a la colección view.Fields.Add(column); } // Cierra el recordset reader.Close(); } }
/// <summary> /// Obtiene un dataTable a partir de un nombre de una sentencia o procedimiento y sus parámetros /// </summary> public DataTable GetDataTable(string sql, ParametersDbCollection parameters, CommandType commandType, TimeSpan?timeOut = null) { DataTable table = new DataTable(); // Carga los datos de la tabla table.Load(ExecuteReader(sql, parameters, commandType, timeOut), LoadOption.OverwriteChanges); // Devuelve la tabla return(table); }
/// <summary> /// Obtiene una colección de parámetros con un único parámetro de tipo entero /// </summary> private ParametersDbCollection GetParameters(string Parameter, int?parameterValue) { ParametersDbCollection parametersDB = new ParametersDbCollection(); // Asigna los parámetros parametersDB.Add(Parameter, parameterValue); // Devuelve los parámetros return(parametersDB); }
/// <summary> /// Convierte un parámetro al índice de ODBC /// </summary> private ParameterDb GetParameterValue(string parameterPrefix, string key, ParametersDbCollection parametersDb, int index) { // Busca el parámetro en la colección foreach (ParameterDb parameter in parametersDb) if (key.Equals(parameter.Name, StringComparison.CurrentCultureIgnoreCase) || key.Equals(parameterPrefix + parameter.Name, StringComparison.CurrentCultureIgnoreCase)) return new ParameterDb("@" + parameter.Name + index.ToString(), parameter.Value, parameter.Direction, parameter.Length); // Si ha llegado hasta aquí, devuelve un parámetro nulo return new ParameterDb("@" + key + index.ToString(), null, System.Data.ParameterDirection.Input); }
/// <summary> /// Carga un objeto utilizando genéricos para un procedimiento con un único parámetro alfanumérico /// </summary> public TypeData LoadObject(string text, string Parameter, string parameterValue, int parameterLength, CommandType commandType, AssignDataCallBack callBack) { ParametersDbCollection parametersDB = new ParametersDbCollection(); // Asigna los parámetros parametersDB.Add(Parameter, parameterValue, parameterLength); // Carga los datos return(LoadObject(text, parametersDB, commandType, callBack)); }
/// <summary> /// Obtiene un dataTable a partir de un nombre de una sentencia o procedimiento y sus parámetros de forma asíncrona /// </summary> public async Task <DataTable> GetDataTableAsync(string sql, ParametersDbCollection parameters, CommandType commandType, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { DataTable table = new DataTable(); // Carga los datos de la tabla table.Load(await ExecuteReaderAsync(sql, parameters, commandType, timeOut, cancellationToken), LoadOption.OverwriteChanges); // Devuelve la tabla return(table); }
/// <summary> /// Obtiene el datatable de una consulta /// </summary> internal async Task <DataTable> GetDataTableAsync(IDbProvider provider, string query, Models.ArgumentListModel arguments, int actualPage, int pageSize, TimeSpan timeout, CancellationToken cancellationToken) { DataTable result = null; // Obtiene la tabla using (BlockLogModel block = Manager.SolutionManager.Logger.Default.CreateBlock(LogModel.LogType.Info, "Execute query")) { if (string.IsNullOrWhiteSpace(query)) { block.Error("The query is empty"); } else { List <ScriptSqlPartModel> scripts = new ScriptSqlTokenizer().Parse(query, arguments.Constants); SparkSqlTools sqlTools = new SparkSqlTools(); ParametersDbCollection parametersDb = ConvertParameters(arguments.Parameters); // Obtiene el datatable foreach (ScriptSqlPartModel script in scripts) { if (script.Type == ScriptSqlPartModel.PartType.Sql) { string sql = sqlTools.ConvertSqlNoParameters(script.Content, parametersDb, "$").TrimIgnoreNull(); if (!string.IsNullOrWhiteSpace(sql)) { // Log block.Info($"Executing: {sql}"); // Obtiene la consulta if (sql.TrimIgnoreNull().StartsWith("SELECT", StringComparison.CurrentCultureIgnoreCase)) { if (pageSize == 0) { result = await provider.GetDataTableAsync(sql, null, CommandType.Text, timeout, cancellationToken); } else { result = await provider.GetDataTableAsync(sql, null, CommandType.Text, actualPage, pageSize, timeout, cancellationToken); } } else { result = await ExecuteScalarQueryAsync(provider, sql, timeout, cancellationToken); } } } } // Log block.Info("End query"); } } // Devuelve la última tabla obtenida return(result); }
/// <summary> /// Obtiene un dataTable a partir de un nombre de una sentencia o procedimiento y sus parámetros /// </summary> public DataTable GetDataTable(string sql, ParametersDbCollection parameters, CommandType commandType, int pageNumber, int pageSize, TimeSpan?timeOut = null) { if (SqlParser == null || commandType != CommandType.Text) // ... si no hay un intérprete de paginación en servidor, se obtiene el DataTable directamente de la SQL { return(GetDataTable(sql, parameters, commandType, timeOut)); } else { return(GetDataTable(SqlParser.GetSqlPagination(sql, pageNumber, pageSize), parameters, commandType, timeOut)); } }
/// <summary> /// Crea la lista de parámetros a pasar a la consulta /// </summary> private ParametersDbCollection ConvertParameters(IDbProvider provider, NormalizedDictionary <object> parameters) { ParametersDbCollection parametersDb = new ParametersDbCollection(); // Convierte los parámetros foreach ((string key, object value) in parameters.Enumerate()) { parametersDb.Add($"{provider.SqlHelper.ParameterPrefix}{key}", value); } // Devuelve la colección de parámetros para la base de datos return(parametersDb); }
//? Está comentado porque Spark SQL no admite las cadenas ODBC con marcadores de parámetros, por eso se utiliza la rutina anterior ///// <summary> ///// Ejecuta una serie de comandos utilizando parámetros de base de datos ///// </summary> //private int ExecuteCommands(List<string> commands, NormalizedDictionary<object> parameters, TimeSpan timeOut) //{ // int scriptsExecuted = 0; // SparkSqlTools sqlTools = new SparkSqlTools(); // ParametersDbCollection parametersDb = ConvertParameters(parameters); // // Ejecuta los comandos // using (SparkProvider provider = new SparkProvider(new SparkConnectionString(Manager.Connection.ConnectionString))) // { // // Abre la conexión // provider.Open(); // // Ejecuta las consultas // foreach (string command in commands) // { // (string sqlNormalized, ParametersDbCollection parameterNormalizedDb) = sqlTools.NormalizeSql(command, parametersDb, "$"); // // Ejecuta la cadena SQL // provider.Execute(sqlNormalized, parameterNormalizedDb, System.Data.CommandType.Text, timeOut); // // Indica que se ha ejecutado una sentencia // scriptsExecuted++; // } // } // // Devuelve el número de comandos ejecutados // return scriptsExecuted; //} /// <summary> /// Crea la lista de parámetros a pasar a la consulta /// </summary> private ParametersDbCollection ConvertParameters(NormalizedDictionary <object> parameters) { ParametersDbCollection parametersDb = new ParametersDbCollection(); // Convierte los parámetros foreach ((string key, object value) in parameters.Enumerate()) { parametersDb.Add("$" + key, value); } // Devuelve la colección de parámetros para la base de datos return(parametersDb); }
/// <summary> /// Obtiene un dataTable a partir de un nombre de una sentencia o procedimiento y sus parámetros /// </summary> public async Task <DataTable> GetDataTableAsync(string sql, ParametersDbCollection parameters, CommandType commandType, int pageNumber, int pageSize, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { if (SqlParser == null || commandType != CommandType.Text) // ... si no hay un intérprete de paginación en servidor, se obtiene el DataTable directamente de la SQL { return(await GetDataTableAsync(sql, parameters, commandType, timeOut, cancellationToken)); } else { return(await GetDataTableAsync(SqlParser.GetSqlPagination(sql, pageNumber, pageSize), parameters, commandType, timeOut, cancellationToken)); } }
/// <summary> /// Ejecuta una sentencia sobre la conexión /// </summary> public int Execute(string text, ParametersDbCollection parametersDB, CommandType commandType = CommandType.Text) { int rows; // Abre la conexión Connection.Open(); // Ejecuta sobre la conexión rows = Connection.Execute(text, parametersDB, commandType); // Cierra la conexión Connection.Close(); // Devuelve el número de registros afectados return(rows); }
/// <summary> /// Ejecuta una sentencia sobre la conexión y devuelve un escalar /// </summary> public object ExecuteScalar(string text, ParametersDbCollection parametersDB, CommandType commandType = CommandType.Text) { object value; // Abre la conexión Connection.Open(); // Ejecuta sobre la conexión value = Connection.ExecuteScalar(text, parametersDB, commandType); // Cierra la conexión Connection.Close(); // Devuelve el resultado return(value); }
/// <summary> /// Ejecuta sobre una conexión para obtener una identidad /// </summary> public int?ExecuteGetIdentity(string text, ParametersDbCollection parametersDB, CommandType commandType = CommandType.Text) { int?intIdentity; // Abre la conexión Connection.Open(); // Ejecuta sobre la conexión Connection.Execute(text, parametersDB, commandType); // Obtiene el valor identidad intIdentity = GetIdentityValue(parametersDB); // Cierra la conexión Connection.Close(); // Devuelve el valor identidad return(intIdentity); }
/// <summary> /// Carga las restricciones de una tabla /// </summary> private async Task LoadConstraintsAsync(SqlServerProvider connection, TableDbModel table, TimeSpan timeout, CancellationToken cancellationToken) { ParametersDbCollection parameters = new ParametersDbCollection(); string sql = @"SELECT TableConstraints.Table_Catalog, TableConstraints.Table_Schema, TableConstraints.Table_Name, ColumnConstraint.Column_Name, ColumnConstraint.Constraint_Name, TableConstraints.Constraint_Type, Key_Column.Ordinal_Position FROM Information_Schema.Table_Constraints AS TableConstraints INNER JOIN Information_Schema.Constraint_Column_Usage AS ColumnConstraint ON TableConstraints.Constraint_Catalog = ColumnConstraint.Constraint_Catalog AND TableConstraints.Constraint_Schema = ColumnConstraint.Constraint_Schema AND TableConstraints.Constraint_Name = ColumnConstraint.Constraint_Name INNER JOIN Information_Schema.Key_Column_Usage AS Key_Column ON ColumnConstraint.Constraint_Catalog = Key_Column.Constraint_Catalog AND ColumnConstraint.Constraint_Schema = Key_Column.Constraint_Schema AND ColumnConstraint.Constraint_Name = Key_Column.Constraint_Name AND ColumnConstraint.Column_Name = Key_Column.Column_Name WHERE TableConstraints.Table_Catalog = @Table_Catalog AND TableConstraints.Table_Schema = @Table_Schema AND TableConstraints.Table_Name = @Table_Name ORDER BY TableConstraints.Table_Name, TableConstraints.Constraint_Type, Key_Column.Ordinal_Position" ; // Añade los parámetros parameters.Add("@Table_Catalog", table.Catalog); parameters.Add("@Table_Schema", table.Schema); parameters.Add("@Table_Name", table.Name); // Carga los datos using (DbDataReader reader = await connection.ExecuteReaderAsync(sql, parameters, CommandType.Text, timeout, cancellationToken)) { // Lee los datos while (!cancellationToken.IsCancellationRequested && await reader.ReadAsync(cancellationToken)) { ConstraintDbModel constraint = new ConstraintDbModel(); // Asigna los datos del registro constraint.Catalog = (string)reader.IisNull("Table_Catalog"); constraint.Schema = (string)reader.IisNull("Table_Schema"); constraint.Table = (string)reader.IisNull("Table_Name"); constraint.Column = (string)reader.IisNull("Column_Name"); constraint.Name = (string)reader.IisNull("Constraint_Name"); constraint.Type = GetConstratype((string)reader.IisNull("Constraint_Type")); constraint.Position = (int)reader.IisNull("Ordinal_Position"); // Añade la restricción a la colección table.Constraints.Add(constraint); } // Cierra el recordset reader.Close(); } }
/// <summary> /// Obtiene el plan de ejecución de una consulta /// </summary> internal async Task <DataTable> GetExecutionPlanAsync(IDbProvider provider, string query, Models.ArgumentListModel arguments, TimeSpan timeout, CancellationToken cancellationToken) { DataTable result = null; // Obtiene la tabla using (BlockLogModel block = Manager.Logger.Default.CreateBlock(LogModel.LogType.Info, "Get execution plan")) { if (string.IsNullOrWhiteSpace(query)) { block.Error("The query is empty"); } else { List <SqlSectionModel> scripts = new SqlParser().Tokenize(query, arguments.Constants.ToDictionary(), out string error); if (!string.IsNullOrWhiteSpace(error)) { block.Error(error); } else { ParametersDbCollection parametersDb = ConvertParameters(provider, arguments.Parameters); // Obtiene el datatable foreach (SqlSectionModel script in scripts) { if (script.Type == SqlSectionModel.SectionType.Sql) { string sql = provider.SqlHelper.ConvertSqlNoParameters(script.Content, parametersDb).TrimIgnoreNull(); if (!string.IsNullOrWhiteSpace(sql)) { // Log block.Info($"Get execution plan: {sql}"); // Obtiene el plan de ejecución result = await provider.GetExecutionPlanAsync(sql, null, CommandType.Text, timeout, cancellationToken); } } } // Log block.Info("End query"); } } } // Devuelve la última tabla obtenida return(result); }
/// <summary> /// Obtiene un IDataReader a partir de un nombre de una sentencia o procedimiento y sus parámetros paginando /// en el servidor /// </summary> /// <remarks> /// Sólo está implementado totalmente para los comandos de texto, no para los procedimientos almacenados /// </remarks> public IDataReader ExecuteReader(string sql, ParametersDbCollection parameters, CommandType commandType, int pageNumber, int pageSize, TimeSpan?timeOut = null) { if (commandType == CommandType.Text && SqlParser != null) { // Crea una colección de parámetros si no existía if (parameters == null) { parameters = new ParametersDbCollection(); } // Obtiene el dataReader return(ExecuteReader(SqlParser.GetSqlPagination(sql, pageNumber, pageSize), parameters, commandType, timeOut)); } else { return(ExecuteReader(sql, parameters, commandType, timeOut)); } }
/// <summary> /// Obtiene un DataReader /// </summary> public IDataReader ExecuteReader(string sql, ParametersDbCollection parametersDB, CommandType commandType, TimeSpan?timeOut = null) { IDataReader reader; // Ejecuta el comando using (IDbCommand command = GetCommand(sql, timeOut)) { // Indica el tipo de comando command.CommandType = commandType; command.CommandTimeout = GetTimeout(timeOut); // Añade los parámetros AddParameters(command, parametersDB); // Obtiene el dataReader reader = command.ExecuteReader(); } // Devuelve el dataReader return(reader); }
/// <summary> /// Obtiene un IDataReader a partir de un nombre de una sentencia o procedimiento y sus parámetros paginando /// en el servidor de forma asíncrona /// </summary> /// <remarks> /// Sólo está implementado totalmente para los comandos de texto, no para los procedimientos almacenados /// </remarks> public async Task <DbDataReader> ExecuteReaderAsync(string sql, ParametersDbCollection parameters, CommandType commandType, int pageNumber, int pageSize, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { if (commandType == CommandType.Text && SqlParser != null) { // Crea una colección de parámetros si no existía if (parameters == null) { parameters = new ParametersDbCollection(); } // Obtiene el dataReader return(await ExecuteReaderAsync(SqlParser.GetSqlPagination(sql, pageNumber, pageSize), parameters, commandType, timeOut, cancellationToken)); } else { return(await ExecuteReaderAsync(sql, parameters, commandType, timeOut, cancellationToken)); } }
/// <summary> /// Ejecuta una sentencia o procedimiento sobre la base de datos y devuelve un escalar /// </summary> public object ExecuteScalar(string sql, ParametersDbCollection parameters, CommandType commandType, TimeSpan?timeOut = null) { object result; // Ejecuta el comando using (IDbCommand command = GetCommand(sql, timeOut)) { // Indica el tipo de comando command.CommandType = commandType; command.CommandTimeout = GetTimeout(timeOut); // Añade los parámetros al comando AddParameters(command, parameters); // Ejecuta la consulta result = command.ExecuteScalar(); } // Devuelve el resultado return(result); }
/// <summary> /// Ejecuta una sentencia o procedimiento sobre la base de datos y devuelve un escalar de forma asíncrona /// </summary> public async Task <object> ExecuteScalarAsync(string sql, ParametersDbCollection parameters, CommandType commandType, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { object result; // Ejecuta el comando using (IDbCommand command = GetCommand(sql, timeOut)) { // Indica el tipo de comando command.CommandType = commandType; command.CommandTimeout = GetTimeout(timeOut); // Añade los parámetros al comando AddParameters(command, parameters); // Ejecuta la consulta result = await(command as DbCommand).ExecuteScalarAsync(cancellationToken ?? CancellationToken.None); } // Devuelve el resultado return(result); }
/// <summary> /// Obtiene un DataReader de forma asíncrona /// </summary> public async Task <DbDataReader> ExecuteReaderAsync(string sql, ParametersDbCollection parametersDB, CommandType commandType, TimeSpan?timeOut = null, CancellationToken?cancellationToken = null) { DbDataReader reader; // Ejecuta el comando using (IDbCommand command = GetCommand(sql, timeOut)) { // Indica el tipo de comando command.CommandType = commandType; command.CommandTimeout = GetTimeout(timeOut); // Añade los parámetros AddParameters(command, parametersDB); // Obtiene el dataReader reader = await(command as DbCommand).ExecuteReaderAsync(cancellationToken ?? CancellationToken.None); } // Devuelve el dataReader return(reader); }
/// <summary> /// Carga una colección paginada utilizando genéricos /// </summary> public List <TypeData> LoadCollection(string text, ParametersDbCollection parametersDB, CommandType commandType, AssignDataCallBack callBack, int page, int recordsPerPage) { List <TypeData> results = new List <TypeData>(); // Abre la conexión Connection.Open(); // Carga los datos using (IDataReader rdoData = Connection.ExecuteReader(text, parametersDB, commandType, page, recordsPerPage)) { while (rdoData.Read()) { results.Add((TypeData)callBack(rdoData)); } } // Cierra la conexión Connection.Close(); // Devuelve la lista return(results); }
/// <summary> /// Obtiene el número de registro de una consulta /// </summary> public long?GetRecordsCount(string sql, ParametersDbCollection parametersDB, TimeSpan?timeOut = null) { if (SqlParser == null) { return(null); } else { object result = ExecuteScalar(SqlParser.GetSqlCount(sql), parametersDB, CommandType.Text, timeOut); if (result == null) { return(null); } else if (result is long) { return((long?)result); } else { return((int?)result); } } }
/// <summary> /// Carga las columnas de una tabla /// </summary> private async Task LoadColumnsAsync(SqlServerProvider connection, TableDbModel table, TimeSpan timeout, CancellationToken cancellationToken) { ParametersDbCollection parameters = new ParametersDbCollection(); string sql; // Añade los parámetros parameters.Add("@Table_Catalog", table.Catalog); parameters.Add("@Table_Schema", table.Schema); parameters.Add("@Table_Name", table.Name); // Crea la cadena SQL sql = @"SELECT Columns.Column_Name, Columns.Ordinal_Position, Columns.Column_Default, Columns.Is_Nullable, Columns.Data_Type, Columns.Character_Maximum_Length, CONVERT(int, Columns.Numeric_Precision) AS Numeric_Precision, CONVERT(int, Columns.Numeric_Precision_Radix) AS Numeric_Precision_Radix, CONVERT(int, Columns.Numeric_Scale) AS Numeric_Scale, CONVERT(int, Columns.DateTime_Precision) AS DateTime_Precision, Columns.Character_Set_Name, Columns.Collation_Catalog, Columns.Collation_Schema, Columns.Collation_Name, Objects.is_identity, Properties.value AS Description FROM Information_Schema.Columns AS Columns INNER JOIN sys.all_objects AS Tables ON Columns.Table_Name = Tables.name INNER JOIN sys.columns AS Objects ON Columns.Column_Name = Objects.name AND Tables.object_id = Objects.object_id LEFT JOIN sys.extended_properties AS Properties ON Objects.object_id = Properties.major_id AND Properties.minor_id = Objects.column_id AND Properties.name = 'MS_Description' WHERE Columns.Table_Catalog = @Table_Catalog AND Columns.Table_Schema = @Table_Schema AND Columns.Table_Name = @Table_Name ORDER BY Ordinal_Position" ; // Carga los datos using (DbDataReader reader = await connection.ExecuteReaderAsync(sql, parameters, CommandType.Text, timeout, cancellationToken)) { // Lee los datos while (!cancellationToken.IsCancellationRequested && await reader.ReadAsync(cancellationToken)) { FieldDbModel column = new FieldDbModel(); // Asigna los datos del registro column.Name = (string)reader.IisNull("Column_Name") as string; column.OrdinalPosition = (int)reader.IisNull("Ordinal_Position", 0); column.Default = (string)reader.IisNull("Column_Default"); column.IsRequired = ((string)reader.IisNull("Is_Nullable")).Equals("no", StringComparison.CurrentCultureIgnoreCase); column.DbType = (string)reader.IisNull("Data_Type"); column.Length = (int)reader.IisNull("Character_Maximum_Length", 0); column.NumericPrecision = (int)reader.IisNull("Numeric_Precision", 0); column.NumericPrecisionRadix = (int)reader.IisNull("Numeric_Precision_Radix", 0); column.NumericScale = (int)reader.IisNull("Numeric_Scale", 0); column.DateTimePrecision = (int)reader.IisNull("DateTime_Precision", 0); column.CharacterSetName = (string)reader.IisNull("Character_Set_Name"); column.CollationCatalog = (string)reader.IisNull("Collation_Catalog"); column.CollationSchema = (string)reader.IisNull("Collation_Schema"); column.CollationName = (string)reader.IisNull("Collation_Name"); column.IsIdentity = (bool)reader.IisNull("is_identity"); column.Description = (string)reader.IisNull("Description") as string; // Añade la columna a la colección table.Fields.Add(column); } // Cierra el recordset reader.Close(); } }