Inserción individual y masiva de registros en SQL Server usando C#

  1. Clase auxiliar de accceso a datos

A continuación se presenta una clase genérica que encapsula las operaciones básicas de base de datos con ADO.NET y SQL Server.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace DataAccess.Helper
{
    public class DataAccessHelper
    {
        private static readonly string connectionString =
            "Server=.;DataBase=FasteningResultDB;Uid=sa;Pwd=123";

        /// <summary>
        /// Ejecuta sentencias INSERT, UPDATE, DELETE.
        /// </summary>
        public static int ExecuteNonQuery(string sql)
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                try
                {
                    conn.Open();
                    return cmd.ExecuteNonQuery();
                }
                catch (SqlException ex)
                {
                    // Registrar error (log)
                    throw new Exception("Error en la operación de base de datos: " + ex.Message);
                }
            }
        }

        /// <summary>
        /// Ejecuta una consulta que devuelve un único valor.
        /// </summary>
        public static object GetScalar(string sql)
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                try
                {
                    conn.Open();
                    return cmd.ExecuteScalar();
                }
                catch (SqlException ex)
                {
                    throw new Exception("Error al obtener escalar: " + ex.Message);
                }
            }
        }

        /// <summary>
        /// Obtiene un SqlDataReader manteniendo la conexión abierta hasta cerrar el lector.
        /// </summary>
        public static SqlDataReader GetReader(string sql)
        {
            SqlConnection conn = new SqlConnection(connectionString);
            SqlCommand cmd = new SqlCommand(sql, conn);
            try
            {
                conn.Open();
                return cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch
            {
                conn.Close();
                throw;
            }
        }

        /// <summary>
        /// Devuelve un DataSet con el resultado de la consulta.
        /// </summary>
        public static DataSet GetDataSet(string sql)
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                SqlDataAdapter adapter = new SqlDataAdapter(sql, conn);
                DataSet ds = new DataSet();
                try
                {
                    conn.Open();
                    adapter.Fill(ds);
                    return ds;
                }
                catch (SqlException ex)
                {
                    throw new Exception("Error al llenar DataSet: " + ex.Message);
                }
            }
        }
    }
}

  1. Inserción de un solo registro

Ejemplo de método que construye una sentencia INSERT a partir de un objeto de datos y la ejecuta.

public int InsertSingleRecord(FasteningResultData data)
{
    // Construir la plantilla SQL
    StringBuilder queryBuilder = new StringBuilder();
    queryBuilder.Append("INSERT INTO FasteningResult (");
    queryBuilder.Append("FasteningID, ProductSN, StationCode, StationName, BoltNumber, ");
    queryBuilder.Append("FasteningStatus, ResultDateTime, FinalTorque, FinalAngle, ");
    queryBuilder.Append("OperateDateTime, OperateFlat, ErrorInfo) VALUES (");
    queryBuilder.Append("'{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}',{10},'{11}')");

    // Asignar valores
    string sql = string.Format(queryBuilder.ToString(),
        "", "", "", data.StationName,
        data.BoltNumber1, data.FasteningStatus1,
        Convert.ToDateTime(data.RealTime),
        data.Torque1, data.Angle1,
        "", 0, "");

    try
    {
        return DataAccessHelper.ExecuteNonQuery(sql);
    }
    catch (SqlException ex)
    {
        throw new Exception("Fallo al insertar registro único: " + ex.Message);
    }
}

La sentencia SQL generada sería similar a:

INSERT INTO FasteningResult(...) VALUES('','','','Stn 01','01','NG','2021/08/29 23:05:42','4.1983','0','',0,'')

  1. Inserción de múltiples registros con UNION ALL

Para insertar varias filas en una sola operación se puede usar UNION ALL dantro de un INSERT ... SELECT. A continuación se muestra un método que itera sobre los pernos disponibles y construye dinámicamente la consulta.

public int InsertMultipleRecords(FasteningResultData data)
{
    // Encabezado común
    StringBuilder baseQuery = new StringBuilder();
    baseQuery.Append("INSERT INTO FasteningResult (");
    baseQuery.Append("FasteningID, ProductSN, StationCode, StationName, BoltNumber, ");
    baseQuery.Append("FasteningStatus, ResultDateTime, FinalTorque, FinalAngle, ");
    baseQuery.Append("OperateDateTime, OperateFlat, ErrorInfo) ");

    // Recopilar datos de cada perno
    var boltDataList = new List<(string boltNumber, string status, string torque, string angle)>();
    boltDataList.Add((data.BoltNumber1, data.FasteningStatus1, data.Torque1, data.Angle1));
    if (data.NumberOfBolts >= 2)
        boltDataList.Add((data.BoltNumber2, data.FasteningStatus2, data.Torque2, data.Angle2));
    if (data.NumberOfBolts >= 3)
        boltDataList.Add((data.BoltNumber3, data.FasteningStatus3, data.Torque3, data.Angle3));
    if (data.NumberOfBolts >= 4)
        boltDataList.Add((data.BoltNumber4, data.FasteningStatus4, data.Torque4, data.Angle4));
    if (data.NumberOfBolts >= 5)
        boltDataList.Add((data.BoltNumber5, data.FasteningStatus5, data.Torque5, data.Angle5));
    if (data.NumberOfBolts >= 6)
        boltDataList.Add((data.BoltNumber6, data.FasteningStatus6, data.Torque6, data.Angle6));

    // Construir la parte SELECT con UNION ALL
    StringBuilder selectParts = new StringBuilder();
    for (int i = 0; i < boltDataList.Count; i++)
    {
        if (i > 0)
            selectParts.Append(" UNION ALL ");
        selectParts.AppendFormat(
            "SELECT '{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}',{10},'{11}'",
            "", "", "", data.StationName,
            boltDataList[i].boltNumber,
            boltDataList[i].status,
            Convert.ToDateTime(data.RealTime),
            boltDataList[i].torque,
            boltDataList[i].angle,
            "", 0, "");
    }

    string fullSql = baseQuery.ToString() + selectParts.ToString();

    try
    {
        return DataAccessHelper.ExecuteNonQuery(fullSql);
    }
    catch (SqlException ex)
    {
        throw new Exception("Fallo al insertar múltiples registros: " + ex.Message);
    }
}

El SQL generado para seis pernos sería algo como:

INSERT INTO FasteningResult(...)
SELECT '','','','Stn 01','01','NG','2021/08/29 23:09:20','4.1983','0','',0,''
UNION ALL SELECT '','','','Stn 01','02','NG','2021/08/29 23:09:20','0','0','',0,''
UNION ALL SELECT '','','','Stn 01','03','OK','2021/08/29 23:09:20','475.19','360.791','',0,''
UNION ALL SELECT '','','','Stn 01','04','NG','2021/08/29 23:09:20','4.5254','0','',0,''
UNION ALL SELECT '','','','Stn 01','05','NG','2021/08/29 23:09:20','4.6731','0','',0,''
UNION ALL SELECT '','','','Stn 01','06','NG','2021/08/29 23:09:20','3.9974','0','',0,''

Etiquetas: C# SQL Server ADO.NET inserción de datos UNION ALL

Publicado el 6-1 21:33