- 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);
}
}
}
}
}
- 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,'')
- 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,''