C# -- Sistema de Gestión de Estudiantes C/S -- Operaciones CRUD de Información Estudiantil

1. Incorporación de un nuevo alumno

a) Capa de acceso a datos (DAL): En el servicio de alumnos, se implementan métodos para verificar la existencia de un documento de identidad y para insertar un nuevo registro.

// ServicioAlumnos.cs
public bool DocumentoIdentidadExiste(string numDocumento)
{
    string consulta = "SELECT COUNT(*) FROM Alumnos WHERE NumDocumentoIdentidad = @NumDoc";
    // Usar parámetros para evitar inyección SQL
    int totalRegistros = Convert.ToInt32(BaseDatosHelper.ObtenerValorUnico(consulta, new SqlParameter("@NumDoc", numDocumento)));
    return totalRegistros > 0;
}

public int InsertarAlumno(Alumno nuevoAlumno)
{
    StringBuilder sentenciaSql = new StringBuilder();
    sentenciaSql.Append("INSERT INTO Alumnos(Nombre, Genero, FechaNacimiento, NumDocumentoIdentidad, ");
    sentenciaSql.Append("Edad, Telefono, Direccion, NumeroTarjeta, IdClase) ");
    sentenciaSql.Append("VALUES(@Nombre, @Genero, @FechaNac, @NumDoc, @Edad, @Telefono, @Direccion, @NumTarjeta, @IdClase)");

    SqlParameter[] parametros = new SqlParameter[]
    {
        new SqlParameter("@Nombre", nuevoAlumno.Nombre),
        new SqlParameter("@Genero", nuevoAlumno.Genero),
        new SqlParameter("@FechaNac", nuevoAlumno.FechaNacimiento),
        new SqlParameter("@NumDoc", nuevoAlumno.NumDocumentoIdentidad),
        new SqlParameter("@Edad", nuevoAlumno.Edad),
        new SqlParameter("@Telefono", nuevoAlumno.Telefono),
        new SqlParameter("@Direccion", nuevoAlumno.Direccion),
        new SqlParameter("@NumTarjeta", nuevoAlumno.NumeroTarjeta),
        new SqlParameter("@IdClase", nuevoAlumno.IdClase)
    };

    try
    {
        return BaseDatosHelper.EjecutarComando(sentenciaSql.ToString(), parametros);
    }
    catch (SqlException ex)
    {
        throw new Exception("Error en la operación con la base de datos: " + ex.Message);
    }
}

b) Interfaz de usuario (UI): El evento del botón de confirmación maneja la validación de los datos del formulario y la comunicación con la capa de datos.

// FrmAgregarAlumno.cs
private void btnConfirmar_Click(object sender, EventArgs e)
{
    // Validaciones de campos requeridos y formato...
    if (string.IsNullOrWhiteSpace(txtNombre.Text))
    {
        MessageBox.Show("El nombre es obligatorio.", "Aviso");
        txtNombre.Focus();
        return;
    }
    // ... más validaciones (género, clase, documento, fecha, etc.)

    // Crear objeto con los datos del formulario
    Alumno alumnoParaGuardar = new Alumno
    {
        Nombre = txtNombre.Text.Trim(),
        Genero = rbMasculino.Checked ? "Masculino" : "Femenino",
        FechaNacimiento = dtpFechaNac.Value,
        NumDocumentoIdentidad = txtDocumento.Text.Trim(),
        Telefono = txtTelefono.Text.Trim(),
        Direccion = txtDireccion.Text.Trim(),
        NumeroTarjeta = txtNumTarjeta.Text.Trim(),
        IdClase = (int)cbClase.SelectedValue,
        Edad = DateTime.Now.Year - dtpFechaNac.Value.Year
    };

    try
    {
        if (_servicioAlumnos.InsertarAlumno(alumnoParaGuardar) == 1)
        {
            MessageBox.Show("Alumno registrado exitosamente.");
            LimpiarControles(); // Método para resetear el formulario
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error");
    }
}

2. Consulta de información de alumnos

a) Modelos de datos: Se definen clases para representar la información básica y extendida de un alumno.

// Modelo Alumno
public class Alumno
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public string Genero { get; set; }
    public DateTime FechaNacimiento { get; set; }
    public string NumDocumentoIdentidad { get; set; }
    public int Edad { get; set; }
    public string Telefono { get; set; }
    public string Direccion { get; set; }
    public string NumeroTarjeta { get; set; }
    public int IdClase { get; set; }
}

// Modelo extendido con datos de la clase
public class DetalleAlumno : Alumno
{
    public string NombreClase { get; set; }
    public int NotaCSharp { get; set; }
    public int NotaSQLServer { get; set; }
}

b) Capa de datos (DAL): Se implementan diferentes métodos de consulta según criterios específicos.

// ServicioAlumnos.cs
public List<DetalleAlumno> ObtenerAlumnosPorClase(string nombreClase)
{
    string consulta = @"SELECT a.Id, a.Nombre, a.Genero, a.FechaNacimiento, c.NombreClase
                        FROM Alumnos a
                        INNER JOIN Clases c ON a.IdClase = c.IdClase
                        WHERE c.NombreClase = @NombreClase";

    List<DetalleAlumno> lista = new List<DetalleAlumno>();
    using (SqlDataReader lector = BaseDatosHelper.ObtenerLector(consulta, new SqlParameter("@NombreClase", nombreClase)))
    {
        while (lector.Read())
        {
            lista.Add(new DetalleAlumno
            {
                Id = (int)lector["Id"],
                Nombre = lector["Nombre"].ToString(),
                Genero = lector["Genero"].ToString(),
                FechaNacimiento = (DateTime)lector["FechaNacimiento"],
                NombreClase = lector["NombreClase"].ToString()
            });
        }
    }
    return lista;
}

public DetalleAlumno BuscarAlumnoPorId(int idAlumno)
{
    string consulta = @"SELECT a.*, c.NombreClase
                        FROM Alumnos a
                        INNER JOIN Clases c ON a.IdClase = c.IdClase
                        WHERE a.Id = @IdAlumno";

    DetalleAlumno alumnoEncontrado = null;
    using (SqlDataReader lector = BaseDatosHelper.ObtenerLector(consulta, new SqlParameter("@IdAlumno", idAlumno)))
    {
        if (lector.Read())
        {
            alumnoEncontrado = MapearDetalleAlumno(lector); // Método auxiliar para mapear
        }
    }
    return alumnoEncontrado;
}

public DetalleAlumno BuscarAlumnoPorTarjeta(string numeroTarjeta)
{
    string condicion = "WHERE a.NumeroTarjeta = @NumTarjeta";
    return ObtenerAlumnoConCondicion(condicion, new SqlParameter("@NumTarjeta", numeroTarjeta));
}

c) Interfaz de usuario: Los eventos de la interfaz invocan los métodos de consulta y muestran los resultados.

// FrmConsultaAlumnos.cs
private void btnBuscarPorClase_Click(object sender, EventArgs e)
{
    if (cbClase.SelectedIndex == -1) return;

    dgvResultado.AutoGenerateColumns = false;
    dgvResultado.DataSource = _servicioAlumnos.ObtenerAlumnosPorClase(cbClase.Text);
}

private void btnVerDetalle_Click(object sender, EventArgs e)
{
    if (string.IsNullOrWhiteSpace(txtIdAlumno.Text)) return;

    DetalleAlumno detalle = _servicioAlumnos.BuscarAlumnoPorId(int.Parse(txtIdAlumno.Text));
    if (detalle == null)
    {
        MessageBox.Show("Alumno no encontrado.");
    }
    else
    {
        FrmDetalleAlumno frmDetalle = new FrmDetalleAlumno(detalle);
        frmDetalle.ShowDialog();
    }
}

d) Formulario de detalles: Muestrra la información completa de un alumno.

// FrmDetalleAlumno.cs
public partial class FrmDetalleAlumno : Form
{
    public FrmDetalleAlumno(DetalleAlumno datos)
    {
        InitializeComponent();
        lblNombreValor.Text = datos.Nombre;
        lblDocumentoValor.Text = datos.NumDocumentoIdentidad;
        lblTelefonoValor.Text = datos.Telefono;
        lblNacimientoValor.Text = datos.FechaNacimiento.ToShortDateString();
        lblDireccionValor.Text = datos.Direccion;
        lblGeneroValor.Text = datos.Genero;
        lblClaseValor.Text = datos.NombreClase;
        lblTarjetaValor.Text = datos.NumeroTarjeta;
    }

    private void btnCerrar_Click(object sender, EventArgs e) => Close();
}

3. Modificación de información de alumnos

a) Capa de datos: Se agrega un método para actualizar un registro y una validación mejorada para el número de documento.

// ServicioAlumnos.cs
public bool DocumentoIdentidadExiste(string numDocumento, int idAlumnoAExcluir)
{
    string consulta = "SELECT COUNT(*) FROM Alumnos WHERE NumDocumentoIdentidad = @NumDoc AND Id != @IdExcluido";
    SqlParameter[] parametros = {
        new SqlParameter("@NumDoc", numDocumento),
        new SqlParameter("@IdExcluido", idAlumnoAExcluir)
    };
    int conteo = Convert.ToInt32(BaseDatosHelper.ObtenerValorUnico(consulta, parametros));
    return conteo > 0;
}

public int ActualizarAlumno(Alumno alumnoModificado)
{
    string sentenciaSql = @"UPDATE Alumnos SET
                            Nombre = @Nombre,
                            Genero = @Genero,
                            FechaNacimiento = @FechaNac,
                            NumDocumentoIdentidad = @NumDoc,
                            Edad = @Edad,
                            Telefono = @Telefono,
                            Direccion = @Direccion,
                            NumeroTarjeta = @NumTarjeta,
                            IdClase = @IdClase
                            WHERE Id = @Id";

    SqlParameter[] parametros = new SqlParameter[]
    {
        new SqlParameter("@Nombre", alumnoModificado.Nombre),
        new SqlParameter("@Genero", alumnoModificado.Genero),
        new SqlParameter("@FechaNac", alumnoModificado.FechaNacimiento),
        new SqlParameter("@NumDoc", alumnoModificado.NumDocumentoIdentidad),
        new SqlParameter("@Edad", alumnoModificado.Edad),
        new SqlParameter("@Telefono", alumnoModificado.Telefono),
        new SqlParameter("@Direccion", alumnoModificado.Direccion),
        new SqlParameter("@NumTarjeta", alumnoModificado.NumeroTarjeta),
        new SqlParameter("@IdClase", alumnoModificado.IdClase),
        new SqlParameter("@Id", alumnoModificado.Id)
    };

    try
    {
        return BaseDatosHelper.EjecutarComando(sentenciaSql, parametros);
    }
    catch (SqlException ex)
    {
        throw new Exception("Error al actualizar: " + ex.Message);
    }
}

b) Interfaz de usuario: Se utilizan diferentes acciones (botones, menú contextual) para iniciar el proceso de edición.

// FrmConsultaAlumnos.cs
private void AbrirFormularioEdicion()
{
    if (dgvResultado.CurrentRow == null) return;

    int idSeleccionado = (int)dgvResultado.CurrentRow.Cells["ColId"].Value;
    DetalleAlumno datosParaEditar = _servicioAlumnos.BuscarAlumnoPorId(idSeleccionado);

    if (datosParaEditar != null)
    {
        FrmEditarAlumno frmEdicion = new FrmEditarAlumno(datosParaEditar);
        if (frmEdicion.ShowDialog() == DialogResult.OK)
        {
            ActualizarVista(); // Refrescar la grilla
        }
    }
}

private void btnEditar_Click(object sender, EventArgs e) => AbrirFormularioEdicion();
private void menuContextualEditar_Click(object sender, EventArgs e) => AbrirFormularioEdicion();

c) Formulario de edición: Realiza la validación y envía los cambios a la capa de datos.

// FrmEditarAlumno.cs
private void btnGuardarCambios_Click(object sender, EventArgs e)
{
    // Validaciones idénticas al formulario de agregar, pero usando DocumentoIdentidadExiste con el ID
    if (_servicioAlumnos.DocumentoIdentidadExiste(txtDocumento.Text, _alumnoActual.Id))
    {
        MessageBox.Show("Este número de documento ya pertenece a otro alumno.");
        return;
    }

    // Crear objeto Alumno con los datos del formulario, incluyendo el Id original
    Alumno alumnoActualizado = new Alumno { /* ... propiedades ... */ };

    try
    {
        if (_servicioAlumnos.ActualizarAlumno(alumnoActualizado) == 1)
        {
            MessageBox.Show("Datos actualizados correctamente.");
            DialogResult = DialogResult.OK;
            Close();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

4. Eliminación de un alumno

a) Capa de datos: El método de eilminación maneja excepciones específicas de la base de datos, como las restricciones de clave foránea.

// ServicioAlumnos.cs
public int EliminarAlumno(int idAlumno)
{
    string sentenciaSql = "DELETE FROM Alumnos WHERE Id = @Id";
    try
    {
        return BaseDatosHelper.EjecutarComando(sentenciaSql, new SqlParameter("@Id", idAlumno));
    }
    catch (SqlException ex)
    {
        if (ex.Number == 547) // Código de error para restricción de FK
        {
            throw new InvalidOperationException("No se puede eliminar el alumno porque tiene registros asociados.");
        }
        throw new Exception("Error de base de datos: " + ex.Message);
    }
}

b) Interfaz de usuario: El botón de eliminación solicita confirmación antes de proceder.

// FrmConsultaAlumnos.cs
private void btnEliminar_Click(object sender, EventArgs e)
{
    if (dgvResultado.CurrentRow == null) return;

    string nombreAlumno = dgvResultado.CurrentRow.Cells["ColNombre"].Value.ToString();
    DialogResult confirmacion = MessageBox.Show(
        $"¿Está seguro de eliminar al alumno '{nombreAlumno}'?",
        "Confirmar eliminación",
        MessageBoxButtons.YesNo,
        MessageBoxIcon.Warning);

    if (confirmacion == DialogResult.Yes)
    {
        int idParaEliminar = (int)dgvResultado.CurrentRow.Cells["ColId"].Value;
        try
        {
            if (_servicioAlumnos.EliminarAlumno(idParaEliminar) == 1)
            {
                MessageBox.Show("Alumno eliminado.");
                ActualizarVista();
            }
        }
        catch (InvalidOperationException ex)
        {
            MessageBox.Show(ex.Message, "Advertencia");
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: " + ex.Message);
        }
    }
}

Etiquetas: C# SQL Server Windows Forms CRUD ADO.NET

Publicado el 7-29 15:43