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