-
Notifications
You must be signed in to change notification settings - Fork 0
Notion Documentation
Propietario: daniel alvarez Etiquetas: Guías y procesos GitHub: https://github.com/danipoal/Bootcamp.NET
-
Ficheros
Tipos NULL
Para que un tipo pueda contener null → int? a = null;
Pero en un operador ternario si intentas asignar a un int un null dará error aunque sea int?. Hay que castear a un int null tal que así → int?a = b>4 ? 5 : (int?) null;
Debug
Puedes mover la flecha para volver a debugear sin tener que volver a ejecutar todo el programa.
Puedes editar mientras debug, le das a recarga activa para guardar los cambios. 🔥 icono
Debug.writeLine(”texto”) → Aparece un log en la salida, no en el output
Sobrecarga de operaciones → funcionA **+**(int a, int b){}
Variable global → Static
En una función para devolver dos valores se usa una tupla
**(int x, int y)** = GetDimensiones()
private static **(int, int)** GetDimensiones()
{
Console.WriteLine("De cuantas dimensiones quieres el tablero? Coloca la dimensión X:");
int.TryParse(Console.ReadLine(), out int x);
Console.WriteLine("Coloca la dimensión Y");
int.TryParse(Console.ReadLine(), out int y);
**return (x, y);**
}Array bidimensional int [ , ] = new int[3,3]
Array de Arrays int[][]
Listas List
.Add() .Remove
Diccionarios → Se le dice explícitamente que va a contener
Dictionary<string, int> = new Dictionary<string, int>
//No hace falta el cast para guardar el valorArchivos
File.readAllText(”url”) → return string or readAllLines return string[]
StreamReader puede usar using
GITHUB
Para volver a una versión anterior → revert en la versión, luego haces un merge a la versión actual quedándote con lo de ahora, y push
Reestablecer → Vuelve a la versión anterior y elimina los demás.
HashTable → key,value de Object
HashTable Pais = new HashTable
Pais["España"] = 47.000.000;
int gente = (int) Pais["España"];Enum → Utilidad en menús
1-Se declara el enum
2- Introduce por consola: “Martes”
3- Se guardara en EDiaSemana como 1 (Se hace el Parse para pasarlo de string a enum y que funcione)
4- Pero para sacarlo hay que castearlo igualmente
enum EDiaSemana
{
Lunes,
Martes
}
static void Main(string[] args)
{
Console.WriteLine("Que dia de la semana es?");
**Enum**.TryParse(Console.ReadLine(), out EDiaSemana eleccion);
Console.WriteLine("Es el dia nº "+ (int) eleccion + 1);
}[Flags]
public enum eFeatures
{
None = 0,
Feature1 = 1,
Feature2 = 2,
Feature3 = 4,
Feature4 = 8
}
Features myFeatures = eFeatures.Feature1 | eFeatures.Feature3;
Console.WriteLine(myFeatures); // Imprime: Feature1, Feature3
Console.WriteLine((int)myFeatures); // Imprime: 5Herencia
public class Persona
string nombre;
public Persona(string nombre)
{this.nombre = nombre;}
public class Empleado : Persona
{
int salario;
public Empleado(string nombre ,int salario) : **base(nombre)**{
this.salario = salario;
}
}class paciente{
Medico medicoAsignado;
public Medico MedicoAsignado{
get;
set{
medicoAsignado=value;
medicoAsignado.pacientes.Add(this);
}
}
}Los objetos se pasan por referencia siempre en una función cuando lo pones en los parámetros.
Casteo en el operador is
if (pers is Medico m)
Medico medico = (Medico)pers; //Aqui si no es medico va a petar
Medico med = pers AS Medico; //Aqui no peta, xo su resultado sera NullFunciones con genéricos
funcion T buscar() where T : Persona
Se usa para trabajar con colecciones, listas… y no tiene porque conectarse a SQL. Es una sintaxis de querries. Hay 2 maneras, SQL inverso o con Lambda expresiones
OrderBy y luego si quieres seguir ordenando por otros campos ThenBy…
C4.1.1 - Aplicaciones de Escritorio.pdf
Informacion
- Label
- LinkLabel
- ProgressBar
- PictureBox
- DataGridBox
- Panel
- TabControl
- ToolStrip
- StatusStrip
Entrada de datos
- TextBox
- RichTextBox
- ListBox (Lista todos visibles)
- ComboBox (Desplegable)
- CheckBox
- RadioButton
- NumericUpDown
- DateTimePicker
Otros
- Button
- ToolTip
- ContentMenuStrip
- **MenuStrip **(Menu Archivo/Editar…)
- Timer (No visible)
- OpenFileDialog
- ScrollBar
- TrackBar
Para añadir elementos a los combos o listas → Items/Coleccion y añades los elementos alli
Enlazar formularios
Hay que declarar la variable de el formulario que queremos mostrar en el archivo de el form principal → NombreForm f = new NombreForm()
Inicializamos el formulario en algunt eventListener o en un click de boton
f.Show(); → Muestra otro formulario
f.Dialog → Abre un modal que impide pulsar el anterior que se queda detras esperando
Actualizar contenido form
UserModal
Panel
Responsive
Propiedad Anchor: Indica a donde esta pegado ese elemento dentro del formulario
Si anclamos todo, se ajusta al tamaño
Propiedad Dock en panel
El elemento ocupa todo el espacio disponible del panel
Hay diferentes como
- Panel → Todo manual
- FlowLayoutPanel → Controles de fila y columna. Se elige la FlowDirection y los WrapContents
- TableLayoutPanel → Cuadricula por fila y columna. Column/RowCount y Column/RowStyles
- SplitContainer → Divide el area en dos paneles ajustables separados por un divisor.
- GoupBox → Contenedor para agrupar elementos
- TabControl →
- Evento dateTime Picker para que este vacio antes de seleccionar
-
Indicar que el valor que contendra el Picker sea nada
this.dateTimePicker1.CustomFormat = " "; this.dateTimePicker1.Format = DateTimePickerFormat.Custom;
-
Creamos un evento que se ejecute cuando el valor cambia
dateTimePicker1.ValueChanged += new EventHandler (dateTimePicker1_ValueChanged); -
En la funcion del evento introducimos la vuelta a short de el formato de el picker
private void dateTimePicker1_ValueChanged(object sender, EventArgs e) { dateTimePicker1.Format = DateTimePickerFormat.Short; }
-
Logica de los Items, Formulario Simple
item.Text → Para ver lo que hay en un campo de input
Para detectar si no hay nada string.IsNullOrWhiteSpace(TypeComboBox.Text) ya que si no hay nada coge un espacio en blanco y no un null, por tanto no sirve == null
checkbox1.checked → Comprueba si esta o no chekeado
Hay dos tipos: Modificador de estructura - Modificador de Datos
Modificador de estructura DDL
Create- Alter- Drop- Truncate
Transacciones TCL
- Bloques con Commit y rollback
Store procedures → Empieza con BEGIN
Acaba con END
Modificador de Datos DML
Insert- Update- Delete
Control de Datos DCL
- A partir de los campos DML puedes activar por ejemplo:
Trigger → A partir de uno de los anteriores
Una BD tiene 2 archivos. Se encuentra en properties/files de la bd
-
.mdf→ Almacena datos de usuario ,columnas, filas, campos, tablas.. -
.ldf→ Almacena registros de transacciones, entradas,…
Estos tienen un tamaño inicial pero se pueden ir incrementando automáticamente si se le indica.
Propiedades→ NAME, SIZE(tamaño actual), MAXSIZE(Se incrementa), FILEGROWTH
-
Creación BD configuración Personalizada
--Crear BD Con Configuración personalizada IF DB_ID('Cibernarium') IS NULL BEGIN CREATE DATABASE Cibernarium ON PRIMARY( --En el archivo primario, el .mdf NAME = Cibernarium, FILENAME = 'C:\temp\SQL\Cibernarium.mdf', --Ruta donde querras guardar el archivo SIZE = 10MB, MAXSIZE = 100MB, FILEGROWTH = 10% --Incremento al alcanzar el MAX ) LOG ON( NAME = Cibernarium_log, FILENAME = 'C:\temp\SQL\Cibernarium.ldf', SIZE = 5MB, MAXSIZE = 50MB, FILEGROWTH = 10% ) PRINT('Creada BD con configuración personalizada') END; GO
-- Modificar la BD, el incremento ALTER DATABASE Cibernarium MODIFY FILE( NAME = N'Cibernarium', --En el archivo con nombre x FILEGROWTH = 15% ); GO
SQL server profiler 20 → SQL server trabaja como un servicio, AGE puede enviar correos electrónicos si pasa algo
- MS Access export a servidor
-
Ir a la BD dentro de el smss
-
Botón derecho → Tasks/Import data/Microsoft Access
-
Seleccionar Archivo
.mdby Next la opción SQL provider
Seleccionar la bd en la que quieres introducir
-
System Database → Es todo el log de las BD que vayamos creando. Hay que truncarla con el tiempo porque guarda mucha información
-
ALTER tablas post creación
CREATE TABLE Productos ( IdProducto INT PRIMARY KEY **IDENTITY(1,1)**, --**Identity(n,m)** Indica que empezara x el valor n con incremento m Nombre VARCHAR(50) NOT NULL, Descripcion VARCHAR(100), Codigo CHAR(10) NOT NULL, -- CHAR RESERVA 10 CARACT Precio_Ud DECIMAL(10,2) DEFAULT 0, Fecha_Alta DATE ) PRINT('TABLA PRODUCTOS CREADA CON ÉXITO'); -- **COMO AÑADIR UN CAMPO A LA TABLA PRODUCTOS**, CON ADD ALTER TABLE Productos **ADD** Stock DECIMAL(10,3); -- COMO MODIFICAR UN CAMPO ALTER TABLE Productos ALTER COLUMN Nombre VARCHAR(75); -- COMO ELIMINAR UNA COLUMNA ALTER TABLE Productos DROP COLUMN Fecha_Alta; -- COMO CAMBIAR EL NOMBRE DE UN CAMPO -- STORE PROCEDURES (PROCEDIMIENTOS ALMACENADOS) -- UN PROCEDIMIENTO DE SISTEMA SE LLAMA EXEC EXEC sp_rename 'Productos.Nombre', 'Nombre_Producto', 'COLUMN';
-
Vistas y funciones para ellas
- TOP(X) → Para cortar la tabla en X opciones
Select TOP(20) * FROM Pedidos ORDER BY FechaPedido DESC;
- Concatenar texto en vista
SELECT (CódPostalDestinatario **+ ' ' +** CiudadDestinatario) as Codigo FROM Pedidos;
- Concatenar int con comillas convierte NO lo convierte en texto
SELECT (FormaEnvío+ ' a' + IdEmpleado) as Codigo FROM Pedidos;
-
Operación aritmética sujeto [Si tiene espacio en blanco ENTRE CORCHETES]
SELECT PrecioUnidad, Cantidad, **(PrecioUnidad*Cantidad) as importe** FROM **[Detalles de pedidos]**;
WHERE: Sirve para 2 cosas
- JOIN Implícito -> Where [Solo se puede poner una vez y condiciones se añaden con AND/OR]
SELECT * FROM Pedidos WHERE PaísDestinatario = 'Alemania' OR …;
FUNCIONES AGREGADO
-
COUNT() → Única función de agregado que NO necesita GROUP BY
-
LIKE → En SQL Server necesita % para indicar hacia que lado buscar
-
SELECT * FROM Pedidos WHERE PaísDestinatario **LIKE 'A%'**;→ Que empiece por A, si es pusiera ‘%ing’ sería que acabara en ing. Contiene = ‘%r%’
-
-
YEAR() → Ver el año de un dato Date
-
SELECT*, YEAR(FechaPedido) as NOMBRE_COLUMNA FROM PedidosSi quieres mes sería MONTH(), DAY()…Funciones que sacan INTs pero si quieres concatenar hay que CASTEAR a String / Sino CONCAT() los concatena independientemente
SELECT 'Mes: '+ **CAST**(MONTH(FechaPedido)**as varchar(2)**) AS NOMBRE_COLUMNA FROM Pedidos;
-
-
LOWER() & UPPER() → Para pasar a mayus o minus
-
CONCAT(INT 1, ‘STRING’, INT 2)
Alias
El WHERE no reconoce los Alias pero por ejemplo el ORDER BY si
❌
SELECT (PrecioU*Cantidad) as Importe FROM Tabla WHERE Importe> 20;✅
SELECT (PrecioU*Cant) as Importe FROM Tabla WHERE (PrecioU*Cant)> 20;En el ORDER BY si reconoce los Alias✅
SELECT (PrecioU*Cantidad) as Importe FROM Tabla ORDER BY Importe> 20;❌
SELECT (PrecU*Cant) as Import FROM Tabla ORDER BY (PrecioU*Cant)> 20;Las vistas se almacenan en views si → CREATE VIEW x AS
- TOP(X) → Para cortar la tabla en X opciones
-
JOINS y Vinculación
-
JOIN Implícito mediante un WHERE:
SELECT * FROM Tabla1, Tabla2 WHERE Tabla1.ID = Tabla2.FkId- Se le puede añadir mas condiciones como un where normal detrás con el AND..
-
INNER JOIN → Devuelve filas que tienen coincidencia en ambas
- Se usan los alias para facilitar cálculos en select y en el propio inner
SELECT p.Destinatario, p.PaísDestinatario, (dp.Cantidad*dp.PrecioUnidad) AS Importe FROM Pedidos p INNER JOIN [Detalles de Pedidos] dp ON p.IdPedido = dp.IdPedido
- Si hay registros que no coinciden en las dos, osea que por ejemplo un FK no se usa, el registro de el Fk no usado no apareceria.
-
LEFT JOIN
- Filas arriba se colocan izquierda[primeras] , filas abajo van derecha[segundas].
- Devuelve todas las de la primera y las coincidencias de la segunda.
SELECT * FROM Maestro M (La de arriba) -> Todo LEFT JOIN Detalle D (La de abajo) -> Solo coincidencia ON M.IdMaestro = D.IdMaestro;
-
RIGHT JOIN → Igual que LEFT pero al revés.
-
FULL OUTER JOIN → Se ve todo y donde no coincide se verá el NULL
- Se ve todo
-
-
Inserción de Registros
-
Si quiero crear tabla con registros directo noCode
-
Vas any tabla → Botón derecho ScriptTableAs/CreateTo/NewEditor
CREATE TABLE [dbo].[Maestro]( [IdMaestro] [int] NOT NULL, [Valor1] [nchar](10) NULL, CONSTRAINT [PK_Maestro] PRIMARY KEY CLUSTERED ( [IdMaestro] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO
-
-
Valores por defecto
INSERT INTO Maestro (IdMaestro, Valor1) Values (9, 'Lleno'), (11,'Lleno'), (12, 'Lleno');
-
VISTA → Para introducir valores a través de una vista
- Recordar que se le puede seguir poniendo Where en estas líneas.
INSERT INTO MaestroBis (IdMaestro, Valor1) SELECT IdMaestro, Valor1 FROM Maestro;
-
-
Funciones Aritméticas + Filtros GroupBy Having
-
Si mezclas un campo normal de tabla con una función, hay que GROUP BY para poder mostrar la info
SELECT p.PaísDestinatario, --Campo Normal SUM(dp.PrecioUnidad * dp.Cantidad) as Importe --Campo que se calcula x group FROM Pedidos p INNER JOIN [Detalles de pedidos] dp ON p.IdPedido = dp.IdPedido GROUP BY p.PaísDestinatario --cols ORDER BY p.PaísDestinatario; --Solo puedes order del goup xk son las cols
-
Filtrar un GROUP BY → para filtrar las columnas que quieres ver
-
GROUP BY p.PaísDestinatario HAVING P.PaísDestinatario <> 'Alemania'= Agrupa los distintos a Alemania
-
-
-
TRIGGERs
-
Estructura Básica
CREATE TRIGGER NombreTrigger ON Tabla FOR **ACCIÓN** AS BEGIN --Acción a realizar END;
Los triggers siempre están asociados a una tabla en específico y tiene que haber un detonante que lo active
-
FOR Insert
- Cuando se realiza un Insert, se crea un objeto INSERTED que es un almacenamiento temporal [Instead of InnerJoin se puede usar WHERE]
CREATE TRIGGER TFacturas ON Facturas FOR INSERT --Cuando haya un insert, el trigger se ejecutará AS BEGIN --Acción a realizar UPDATE F --Actualizara el registro Sumandole 100 al importe SET F.Importe = F.Importe + 100 FROM Facturas F --El inserted objeto que se guarda de lo que se insertó **INNER** JOIN **inserted** I ON F.IdFactura = I.IdFactura; --Hay que juntar la tabla temporal inserted con la normal END;

-
Otro ejemplo simple
CREATE TRIGGER TFacturasI ON Facturas FOR INSERT AS BEGIN INSERT INTO Registro(Fecha, Descripcion, Usuario) --Introducimos la fecha del sistema y el Usuario que hemos iniciado en sql VALUES(GETDATE(), 'Alta de factura', USER_NAME) END;
Para saber que tiene que actualizar con el ID que hemos insertado, consultamos el objeto INSERTED que contiene el Id que nos interesa, y se lo pasamos Trigger.
- Para comprobar miraríamos en la tabla los Trigger que tiene asignado dicha tabla.
s
-
Modificar Trigger
**ALTER** TRIGGER NUMERO_FACTURA ON Facturas FOR INSERT AS BEGIN UPDATE F SET F.NumeroFactura = CONCAT(F.IdFactura , '/' , YEAR(GETDATE() ) ), F.Cliente = 'CLI' + F.Cliente --Modificacion añadida que introducimos: FROM Facturas F INNER JOIN inserted I ON F.IdFactura = I.IdFactura END; --Se elimina con drop
-
FOR Update
CREATE TRIGGER MFacturas ON Facturas AFTER UPDATE --Se podria hacer FOR, pero lo queremos despues AS BEGIN UPDATE F SET F.Importe = F.Importe - 20 FROM Facturas F INNER JOIN inserted I ON F.IdFactura = I.IdFactura; --Inserted sirve para Update tambien END;
-
Update
- UPDATE
UPDATE Tabla SET Columna = Valor
- UPDATE
-
FOR Delete
CREATE TRIGGER REGISTRO_ELIMINADO ON Facturas FOR **DELETE** AS BEGIN INSERT INTO Registro(Fecha, Descripcion, Usuario) --Introducimos la fecha del sistema y el Usuario que hemos iniciado en sql VALUES(GETDATE(), 'Factura eliminada', USER) END; --Eliminar registro cn ID=3 DELETE FROM Facturas WHERE IdFactura = 2;
-
Objeto deleted (Similar al inserted)
- Puedes en el Trigger hacer un
Select * FROM deletedpara verlo - deleted.Nombre_Columna
- Puedes en el Trigger hacer un
-
Objeto deleted (Similar al inserted)
-
-
Procedimientos
-
Estructura
CREATE PROCEDURE NombrePorcedure @NombreVariable INT AS BEGIN UPDATE ... RETURN ; --Puedes hacer que te retorne un SCOPEIDENTITY -- Para que te saque la **vista** del valor editado END; EXEC NombrePorcedure @NombreVariable= 1
-
Se encuentran en programability/Stored procedures
-
Ejemplo de Update
Enunciado: CREAR UN STORE PROCEDURE QUE INCREMENTE EL VALOR DEL IMPORTE DE LA TABLA FACTURAS SEGUN UNA VARIABLE, Y QUE LO EJECUTE EN FUNCIÓN DE IDFact INDICADO Y DEL VALOR DEL IMP A INCREMENTAR
CREATE PROCEDURE IncrementoImporte @IdFactura INT, @Incremento DECIMAL(12,2) AS BEGIN UPDATE F SET F.Importe = F.Importe + @Incremento FROM Facturas F WHERE F.IdFactura = @IdFactura END; EXEC IncrementoImporte @IdFactura = 1, @Incremento = 20;
-
Ejemplo de Insert + Variables
--Crear un store procedure que pasando un nombre de cliente e importe aleatorio INSERTE --Un registro en la tabla facturas y inserte en la tabla registro un nuevo registro --cn descripcion 'la suma importe de todas las facturas = x SUM(F.importe)' ALTER PROCEDURE InsertarFactura @NombreCliente VARCHAR(100), @Importe DECIMAL(12,2) AS BEGIN INSERT INTO Facturas(Cliente, Importe) VALUES(@NombreCliente, @Importe); DECLARE @in INT; SELECT @in = SUM(Facturas.Importe) FROM Facturas; INSERT INTO Registro(Fecha, Descripcion, Usuario) VALUES (GETDATE(),CONCAT('la suma importe de todas las facturas ES ', @in), USER); SELECT * FROM Registro WHERE Registro.IdRegistro = **SCOPE_Identity()**; --El id de la ultima accion realizada la guarda en scope END; EXEC InsertarFactura juanito, 299;
-
Otro ejemplo Variable
CREATE PROCEDURE GuardarAcumulado AS BEGIN INSERT INTO Facturas(Cliente, Importe) VALUES ('Mengati', 23) DECLARE @acumulado DECIMAL(12,2); SET @acumulado = (SELECT SUM(Importe) FROM Facturas); END;
-
-
-
Variables
Para introducir el resultado de un SELECT en una variable se pasaría así
SELECT @nombreVariable = campoQueQuiero FROM miTabla -
Insert de una Vista (bucle de inserts)
INSERT INTO Articulo(Campo1, Campo2, Campo3) SELECT a1, a2, a3 FROM tabla2
- Crear tabla a partir de una vista
SELECT ... INTO TablaCrear FROM tablaVista
-
Pdfs
C3.1.1 - Generalidades de las bases de datos.pdf
C3.1.1 - Generalidades de las bases de datos.pdf
C3.2.1 - Diseño de bases de datos relacionales (1).pdf
C3.2.3 - Herramientas de Bases de Datos.pdf
C3.2.4 - Crear una Base de Datos.pdf
C3.3.1 - Construcción de Consultas (1).pdf
En Archivo se guarda el fichero directamente y se tiene que abrir, guardar y cerrar. Solo lo puede abrir una persona a la vez. Por eso se usa servidor, para que gestione múltiples peticiones y acceso.
Base de datos de Archivo
- SQLite → Relacional
- Access
- LibreOffice Base
Base de datos de Servidor
- Servidor que es el Software que conecta con la BD que contiene ese ordenador.
SQL vs NoSQL → El Sql tiene muchas reglas que hacen que los datos sean consistentes, que no se puedan introducir por ejemplo pedidos de un usuario que no esta creado. O Rollback cuando una transacción falla por la mitad. En NoSql da igual, se lo traga todo pero puede ser en sitios que no sea requerida tanta seguridad, p.e. Big Data en que un dato incorrecto no cambiará mucho la tendencia.
Diseño: (Especificación requisitos) Conceptual →*(Esquema)* Lógico → Físico (DB Administrator)
Cardinalidad


- Se lee de izquierda a derecha, un Cliente tiene N Factura
- Se juntan las dos para ver el tipo de cardinalidad
Nombre tablas en singular(Convención C#).
Relación Ternaria
Hay veces que en una relación N:M en caso de que necesitemos siempre por ejemplo 2 valores de una tabla, hacemos dos relaciones y dos FK en vez de hacier la N:M
-
Duplicados→ Intentar repetir la menor información en las tablas por registros
- Campo Continente, Varchar → “Europa”, “EUR”, “EUROPA” se podrían duplicar el String de diferentes maneras. Gestionar con una lista desplegable. ej. tabla PAISES
- Asignar a cada valor un numero. 1-Africa, 2-Asia,… Y Campo continentes, INT. Soluciono espacio guardado para cada pías. Y esa clave valor sería una nueva tabla que asociamos.
-
Datos atómicos en Relaciones
-
N:M → Se pone tabla intermedia y se eliminan FK en las otras.
- Ej. Si un país tiene muchos idiomas, y esos idiomas se pueden hablar en muchos países, Muchos a muchos.
-
1:N → Se pone el FK en la tabla que contiene el 1 de el otro.
- Ej. Película solo tiene un director y los directores tienen muchas películas.
-
N:M → Se pone tabla intermedia y se eliminan FK en las otras.
-
Cardinalidad Extendida
Para saber si las FK pueden ser Null o no.
Se hacen poniendo : y si es 1 o 0 en la relación de cada lado.
-
INTEGRIDAD REFERENCIAL (eliminación fk referenciadas)
No permite eliminar filas en las que su id esta como fk en otra tabla. Se puede configurar opción en cascada, para eliminar todos los registros que tenían como fk el que se había eliminado.
- Manera de arreglarlo 1 : Gestionar primero todos los valores que se eliminaran, se gestionan antes.
- Manera de arreglarlo 1 : Set null → Se pone en null todo lo que colgaba de ese id en fk
Clave primaria → Podría ser compuesta de varios campos
En tablas intermedias, la Primaria es la compuesta de FK
Integridad referencial → Restricción en que se referencia Pk con Fk que hace que x ejemplo no se pueda poner Fk un int que no existe en la Pk
VALORES
ARCHIVOS → VarBinary(max), no usar image(deprecated)
-
nvarchar vs varchar
→ Unicode ocupa el doble que no Unicode, mas bytes, la longitud max que puede ocupar además es la mitad.
ASCII → Regla paridad para detectar errores, 8 bits se usan 7 y el ultimo se coloca para que sea par y si hay una interferencia que ve que no es par entonces el ordenador sabe que esta mal.
Mas tarde se añadió el ASCII extendido cuando había otras maneras de detectar errores, 128 caracteres mas.
Imagina en china que hay mil valores→ Se usó Unicode, ocupa mas bytes y en esos mismos se indica si tendrá que usar mas. Si hay que internacionalizar mucho la BD se usaran estos, osea nvarchar.
-
Creación Tablas MMS
→ Visualización diagrama → Database Diagrams/New diagram/
Pasos:
1- Añadir la PK de los campos id
2- Poner que si en Identity Specification/IsIdentity → Activa Autoincrement y indica que es un id técnicamente
3- Relación: En la visualización Diagrama arrastrar la Fk al Pk de otra tabla

Para que te deje editar una tabla una vez creada
Schema → El punto que aparece delante de todas las tablas, diagramas, funciones… Ej: dbo.Diagrama . En MySQL schema es diferente, es la bd, en sqlsmss diferente.
Si es una clave compuesta → CONSTRAINT PK_X PRIMARY KEY (ID, LAST_NAME) p.e.
Y compuesta en FK → Constraint Foreing key references
Alter → Alter Table x alter column x typeData;
Operadores
UNION y EXCEPT → Para sumar consultas o restar
- Requisitos para unir
- = filas dos lados
Union coge solo una, union All coge los duplicados
EXCEPT→ De las 2 querries solo coge lo común
-
Inserción de SUBQUERRYS
Para crear la tabla
SELECT INTO(Se introducen valores de la tabla referenciada) y luegoINSERT INTO**SELECT** CONCAT(first_name, ' ', last_name) as 'Nombre', 'Employee' as 'Type' **INTO** personsDani FROM employees **INSERT INTO** personsDani SELECT CONCAT(first_name,' ', last_name) as 'Nombre', 'Dependant' as 'Type' FROM dependents
-
Update
-
Para modificar valores de columnas
UPDATE Tabla SET columna = 'a' + columna --Se le añade a a todas las filas --Añadimos un where para filtrar
-
Modificar múltiples valores (Separar por comas, pero el SET solo 1 vez)
UPDATE Tabla SET columna = 'a' + columna, columna2= 'j' + columna2 WHERE columna2 LIKE 'T*'
-
Modificación con subquerry o inner join
UPDATE employees SET first_name = '*' + first_name WHERE department_id = *(SELECT department_id FROM departments d WHERE d.department_name LIKE 'M%')*
Es lo mismo que :
UPDATE employees SET first_name = '*' + first_name FROM employees INNER JOIN departments ON employees.department_id = departments.department_id WHERE department_name LIKE 'T%'
-
-
Delete
Borrar de una tabla →
DELETE FROM Personas WHERE first_name LIKE '*%'- Si hay mas tablas implicadas,
DELETE tabla FROM…(Implicación de tipo JOIN)
DELETE e FROM employees e INNER JOIN departments d ON e.department_id = d.department_id WHERE department_name LIKE 'T%'
- Si hay mas tablas implicadas,
-
Funciones agregadas - GROUP BY
SELECT department_name, COUNT(*)FROM employees e INNER JOIN departments d ON e.department_id = d.department_id GROUP BY d.**department_name**;
Problema: Aquí si agrupas por nombres en vez id, puede haber problemas de duplicado por si hay dos dept que se llamen igual pero son diferentes en verdad, los va a tratar como iguales
Solución: AÑADIR en el GROUP BY también la regla mas fuerte,
GROUP BY department_name, department_idpor 2 valoresEl orden es indiferente, irá haciendo paquetes de grupos y irá revisando los valores a ver si los puede segmentar aún mas, pero para ponerlo en el SELECT, tiene que estar en el GROUP BY.
**
HAVING**→ Para filtrar en un GROUPDeja poner funciones agregadas en el filtro, sino usas el where antes del el group y ya esta.
-
JOINs
-
Inner Join, right, left
-
Outer full
-
Cross join → Cada tabla se combina, si hay 2 filas y 4 filas = 2x4=8 registros
Por cada valor de la tabla 1 se harán opciones de la tabla 2
-
Ejemplo de Cross
Tabla 1
1 Juan 2 Maria Tabla 2
1 Barcelona 2 Madrid Tabla resultante
1 Juan 1 Barcelona 1 Juan 2 Madrid 2 Maria 1 Barcelona 2 Maria 2 Madrid
-
-
-
Funciones
Se guardan en programability, y se ejecutan con SELECT, no pueden modificar datos de las tablas creadas en la bd, solo la virtual que genera la función.
Botón derecho en Scalar y crear new function.
- ExecuteScalar → Devuelve 1 valor de la 1 columna de la 1 fila de los datos modificados
- inline-statement →
- multi-statement
La función pertenece a una BD, no se puede usar fuera.

2 maneras de asignar valores a variables
SELECT @NumEmps= COUNT(*) FROM employees Set @NumEmps = (SELECT COUNT(*) FROM employees)
-
maneras de case IF
--Si coge null que devuelva todos IF @dept IS NOT NULL SELECT @NumEmps= COUNT(*) FROM employees e INNER JOIN departments d ON d.department_id = e.department_id WHERE d.department_name LIKE '%' + @dept + '%' ELSE SELECT @NumEmps= COUNT(*) FROM employees e INNER JOIN departments d ON d.department_id = e.department_id --Set @NumEmps = (SELECT COUNT(*) FROM employees) --Segunda manera SELECT COUNT(*) FROM employees e INNER JOIN departments d ON d.department_id = e.department_id WHERE @dept IS NULL OR d.department_name LIKE '%' + @dept + '%' ; --Comprueba que no sea null y devuelve todo, sino aplica el like --Un where es un if, si se cumple el filtro, devuelve lo que se cumple, else no --Tercera subquery [Con subquerry] SELECT COUNT(*) FROM employees e WHERE (@dept IS NULL OR e.department_id IN ( SELECT d.department_id FROM departments d WHERE d.department_name = @dept ); --Cuarta manera [CASE WHEN] SELECT COUNT(*) FROM employees e INNER JOIN departments d ON d.department_id = e.department_id WHERE @dept = CASE WHEN @dept IS NOT NULL THEN d.department_name ELSE NULL END --Quinta manera [case de primeras (subconsultas)] SET @NumEmps = CASE WHEN @dept IS NULL THEN (SELECT COUNT(*) FROM employees) ELSE (SELECT COUNT(*) FROM employees e INNER JOIN departments d ON d.department_id = e.department_id WHERE d.department_name LIKE '%' + @dept + '%' ) END;
Vista view
CREATE VIEW vista1 as SELECT * FROM tabla1;
Diferencia vista y inline-function, que la vista no acepta parametros
-
Procedimientos
#Tabla temporal
-
Ejemplos
CREATE PROCEDURE ListaEmpleadosSPdani AS BEGIN SET NOCOUNT ON; --Para evitar que aparezca lo de x row affected -- Insert statements for procedure here UPDATE employees SET salary = salary + 0.01 END GO --uso exec SELECT first_name, salary from employees; exec ListaEmpleadosSPdani SELECT first_name, salary from employees; --Incrementar en x% a los emp de un dept o todos if null CREATE PROCEDURE IncrementoPorcentajeDani @porcentaje decimal(4,2), @dept int AS BEGIN SET NOCOUNT ON; UPDATE employees SET salary = salary + salary * @porcentaje WHERE @dept IS NULL OR department_id = @dept END SELECT first_name, salary, department_id from employees ORDER BY department_id; exec IncrementoPorcentajeDani 0.02, 1 SELECT first_name, salary, department_id from employees ORDER BY department_id; --Crear funcion que añada un job por param CREATE PROCEDURE AñadirTrabajoDani @nombre varchar(50), @salarioMax decimal(8,2) , @salarioMin decimal(8,2) as BEGIN SET NOCOUNT ON; INSERT INTO dbo.jobs(job_title, max_salary, min_salary) VALUES(@nombre, @salarioMax, @salarioMin); END EXEC AñadirTrabajoDani 'paleto', 2.20,0.00; -- * crea una tabla temporal (#miTabla) donde copia los empleados -- * examina uno por uno estos emps, y elimina los que tiene salario >15000 -- * devolver la tabla final ALTER PROCEDURE ExaminaTrabajoDani as BEGIN DECLARE @count INT; SELECT * INTO #miTablaDan FROM dbo.jobs; SET @count = (SELECT COUNT(*) FROM #miTablaDan) ; WHILE @count > 0 BEGIN DECLARE @salary DECIMAL(8,2) SET @salary = ( SELECT max_salary FROM #miTablaDan WHERE max_salary > 15000 and job_id = @count ) IF @salary IS NOT NULL DELETE FROM #miTablaDan WHERE job_id = @count; SET @count = @count - 1 END select * FROM #miTablaDan ORDER BY max_salary; DROP TABLE #miTablaDan END EXEC ExaminaTrabajoDani
-
tablas
table-rows que contiene tabla-data Atributoscolspan y rowspan
JAVASCRIPT
document, window…
Se pueden poner en los event listener las funciones.
onload
onclick
onsubmit → Si quieres interactuar con un form, pero que deje de hacer el post. event.preventDefault() para que deje de actuar como si haciera un get siempre.
Otra manera es poner type= button en todos los botones y ya no haran el submit.
Canvas
-
moveTo(x, y): Mueve el "pincel" a la posición(x, y)sin dejar un trazo. -
lineTo(x, y): Dibuja una línea desde la posición actual del pincel hasta la posición(x, y)
DAL → Metodos interaccion sql, insert….
Gestionar db.null.value ya que no es lo mismo que NULL normal
-
Conexion basica (SQL DB en Form)
- Se hace una variable que sera connection, se asigna en el constructor.
- Al pulsar ConnectBtn se inicia la conexion. Añadir
MessageBox.showel trigger pulsador - Si no hay conexion, disconnectBtn no se puede pulsar →
disconnectBtn.Enabled
public partial class Form1 : Form { public SqlConnection Connection; public Form1() { InitializeComponent(); string connectionString = @" Data Source=85.208.21.117,54321;" + "Initial Catalog=AriEmployees;" + "User ID=sa;" + "Password= Sql#123456789;" + "TrustServerCertificate=True;"; Connection = new SqlConnection(connectionString); disconnectBtn.Enabled = false; } private void connectBtn_Click(object sender, EventArgs e) { try { Connection.Open(); MessageBox.Show("Conexión establecida con éxito."); } catch (Exception ex) { MessageBox.Show($"Error al conectar: {ex.Message}"); } finally { UpdateConnectionButtons(); } } private void disconnectBtn_Click(object sender, EventArgs e) { try { Connection.Close(); MessageBox.Show("Conexión cerrada."); } catch (Exception ex) { MessageBox.Show($"Error al desconectar: {ex.Message}"); } finally { UpdateConnectionButtons(); } } private void UpdateConnectionButtons() { // El botón de conectar estará habilitado solo si la conexión está cerrada connectBtn.Enabled = Connection.State == ConnectionState.Closed; // El botón de desconectar estará habilitado solo si la conexión está abierta disconnectBtn.Enabled = Connection.State == ConnectionState.Open; } }
-
Sentencias*(Con Form)*
-
Objeto connection necesario. Se podria ir pasando por parametros el ya abierto. Es mejor crear una clase DAL que gestione ese objeto y las sentencias SQL.
-
Hay que cerrar y abrir conexion constantemente, no dejarla abierta (Aunque en el primer ejemplo la dejare abierta)
-
Creación objeto que se sacará de DB
En el objeto hay que tener en cuenta si será null o no.
internal class Job { public string Id { get; set; } public string Titulo { get; set; } public decimal**?** MinSalary { get; set; } public decimal**?** MaxSalary { get; set; } public Job() { } public Job(string id, string titulo, decimal? minSalary, decimal? maxSalary) { Id = id; Titulo = titulo; MinSalary = minSalary; MaxSalary = maxSalary; } }
-
Select
- Generamos el string de la sentenica y la introducimos en el objeto sqlCommand
- Usamos sqlReader para extraer la info del comando
public List<Job> getJobs() { List<Job> jobs = new List<Job>(); string query = "SELECT * FROM jobs"; SqlCommand sqlCommand = new SqlCommand(query, Connection); //Se usa un lector para leer la extraccion de dichos datos. SqlDataReader reader = sqlCommand.ExecuteReader(); //Leemos filas devueltas, uno x uno while (reader.Read()) { //reader.Get espera el indice de columna, no el nombre //Por lo tanto hay encontrar el indice y luego usarlo int jobIdIndex = reader.GetOrdinal("job_id"); int jobId = reader.GetInt32(jobIdIndex); string jobName = reader.GetString(reader.GetOrdinal("job_title")); int minIndex = reader.GetOrdinal("min_salary"); int maxIndex = reader.GetOrdinal("max_salary"); decimal? minSalary = reader.IsDBNull(minIndex) ? null : (decimal?)reader.GetDecimal(minIndex); decimal? maxSalary = reader.IsDBNull(maxIndex) ? null : (decimal?)reader.GetDecimal(maxIndex); Job job = new Job(jobId, jobName, minSalary, maxSalary); jobs.Add(job); } reader.Close(); return jobs; }
- Rellenamos el GridView con la lista del Select:
dataGridView.DataSource = jobs;
-
Insert
-
Se genera la cadena string query y se pasa a SqlCommand
-
Se crean los parametros que recibe(nombre, tipo, tamaño)
- Se añade parametro en el SqlCommand →
insertar.Parameters.Add() - Se le da un valor a ese param →
ptitle.Value = job.Titulo; - En caso que pueda haber un NULL, hay que gestionar ya que el valor que se le pasa a la tabla es DBNull.Value y no null .
- Se añade parametro en el SqlCommand →
-
Si quieres que te devuelva el ID de lo que insertas →
ExecuteScalary en la query al final SELECT SCOPE_IDENTITY() -
Se ejecuta el querry en un try
public void CrearTrabajo(Job job) { String cadena = @" INSERT INTO jobs(job_title, min_salary, max_salary) VALUES (@ptitle, @pminsalary, @maxsalary)"; SqlCommand insertar = new SqlCommand(cadena, Connection); //Generamos el parametro que iran en los valores de la cadena SqlParameter ptitle = new SqlParameter("@ptitle", SqlDbType.VarChar, 35); insertar.Parameters.Add(ptitle); ptitle.Value = job.Titulo; //Se gestiona teniendo en cuenta que puede ser null SqlParameter pminsal = new SqlParameter("@pminsal", SqlDbType.Decimal); insertar.Parameters.Add(pminsal); pminsal.Precision = 8; pminsal.Scale = 2; if (job.MinSalary == null) pminsal.Value = DBNull.Value; else pminsal.Value = job.MinSalary; //Ejecutamos try { insertar.ExecuteNonQuery(); } catch (Exception ex) { MessageBox.Show($"Error al conectar: {ex.Message}"); } }
Por ultimo generariamos en el eventListener la creación del objeto job a traves del formulario que le hemos pasado, y despues pasamos el job completo a la función Crear trabajo.
-
Diferencia
.AddWithValuey.Adden SqlParameter -Add : Hay que hacer mas pasos, especificar tipo de campo y tamaño, control total-WithValue: Mas directo (”@nombrevar”, valor) SQL Injection → Para evitar problemas de esto, se usa el SQLparameters y se introduce ese parametro en las variables precedidas de un @. No hay diferencia de usar un add o withVal.
-
-
ExecuteScalar Tener + control sobre el TableGridView en los elementos de la bd
Hay que recuperar id de lo que hemos insertado, despues del insert into, se hace select scope_identity para recuperar el Id
-
Execute Scalar, como query pero devuelve un object que casteamos a int que es el id. - Se recupera el id, y se lo asignamos a el objeto job que hemos insertado.
-
-
Pdfs
C6.2.5 ASP_NET De WebForms a MVC.pdf
C6.2.1 ASP_NET MVC (Patron y Vista Principal).pdf
C6.2.2 ASP_NET MVC (Vistas y Modelos).pdf
C6.2.3 ASP_NET MVC (Controladores).pdf
En .aspx → Tiene HTML y C#
El servidor es IIS Internet Information Service (Igual que tomcat para java pues este es para C#)
Se usa para información/web dinámica
- Ejemplo WebForm
- Hya que indicar lenguaje
- Ubicación de archivo C# que seria el code behind
Controles de servidor
Todo ira con runat=”server” para que se procese en el lado del servidor
-
Creación de un WebForm
(Si la plantilla no esta, hay que ir a componentes individuales y poner plantillas, y descargar plantillas de proyecto de net framework)
- Plantilla app Web ASP.NET NETframework
- Elegir opción webForms (sin editar ninguna opción)
Estructura carpetas
En la carpeta Content, hay los componentes de bootstrap ya creados.
Default.aspx → La pagina de codigo inicio
Al desplegarlo hay dos archivos el .cs y el designer.cs
Añadimos en el default los componentes, y luego aparecen declarados en el designer
Al iniciar es posible que no funcione por culpa del ssl en chrome, usar edge.
MasterPage (siteMaster):
Seria como el contenido que envuelve todo en todas las paginas. Como la navBar del principio. Dentrod e esta se carga todo lo demas.
Esta si que es html normal
Tiene un elemento ContentPlaceHolder
No tiene extension aspx
PageContent
Tiene un asp:Content que ira justo donde estaba el placeHolder de la Master.
Se declara arriba de el todo como ira
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="PrimerEjemplo._Default" %>
Abajo hay 3 pestalas para ver codigo, diseño (ver lo que apareceria), y dividir para ver las dos
Si no estan → herramientas/opciones/diseñadorWebForms seleccionar entre el hereado y live preview. Si no mirar mejor en google
A la izquierda esta la tabla de herramientas para elegir los componentes/label..
EVENTOS → Igual que en winforms, hay para colocar eventos en el componente
PostBack → Se carga todo una sola vez y luego hay pequeñas recargas?
AutoPostBack → En el html para indicar que eso hara una recarga
if(isPostBack) → Si la ejecución es una recarga
RAZOR
Colocar codigo C# directamente en el html. Entre <% %>
Guardar una variable de sesion
La sesion es ya cuando se conecta a la web
Session [”miVariable ”] = valor; → Iniciar variable
<% =miVariable %> → Recuperar en el html el valor
Ejemplo
Session["user"] = userName;
<%= (string)Session["user"] %>Código
Moverse a otra pagina → Response.Redirect("logIn.aspx")
Componentes:
- Literal → Se puede crear a traves de un Literal object, que es un inerhtml en el que puedes poner C#
- Objeto → Se crea el objeto boton y le añades a posterior los atributos .ID, cssClass, ….
States → ViewState
-
teoria flujo + tips
Modelo .> Datos y logica de negocio
Vista → Lo que se ve en Razor .cshtml
Controlador → Solicitudes entre modelo y vista .cs
Llama a el servicio (donde llama a la bd)y son pocas lineas
Tambien puede haber viewModel
Patron arquitectura ≠ Patron de diseño
1 → Distribuir el codigo en la app
2 → Dsitribuyes bdd…, que se usa apis, …
→ Crear MVC
Nuevo proyecto/ ASP.NET Core (Modelo-Vista-Controlador)
Eliminar el check de hablitar https si quieres que no de problemas crhome, sino usar edge
Estructure:
wwwroot → Estilos, js, img,… Cosas no compilables
Program.cs → main()
Cada vez que se crea un controlador, hay que crear una carpeta con el mismo nombre para la vista. EL nombre tendra que ser sin el Controller ya que esta palabra es reservada para controladores. Si hay fallos de gramatica fallará.
Views/Shared/Layout.cshtml
-
RAZOR
Code blocks →
@{}seria la palabra de escape para insertar el C# en el javascriptTagHelper → literalmente etiquetas pero que se entienden como
asp-for = “model.one” → Estara integrado al modelo
html helpers→
@Html.LabelFor(model ⇒ model.Username)tag →
<input asp-for=”Username”> -
MODEL
ViewModel
Si tienes que recoger información de tablas diferentes de la bd, el modelo recogera esa info de las diferentes fuentes y se hace el modelo pensando en lo que necesitara la vista
El view model puede aprovechar los otros modelos que estan ehchos para cada tabla unica
El using sirve para que puedas escoger cosas de esa ubicación url
@using PrimerMVC.Models.ViewModels @model AnimalesViewModel
- Ejemplo sencillo Modelo Controlador ViewModel
-
Crear el modelo que en este caso sera un modelView
public class AnimalesViewModel { public List<string> Animales { get; set; } = new List<string>(); public AnimalesViewModel() { Animales = new List<string> { "Elefante", "Tigre", "Leon", "Jirafa", "Riniceronte", "Oso panda", "Koala", "Cehekioi", "Canguro", "Aguila" }; } }
-
Generar el Controller para que se inicialize la instancia del modelo
using PrimerMVC.Models.ViewModels; public IActionResult Index() { AnimalesViewModel viw = new AnimalesViewModel(); return View(viw); }
-
Meter la información en la vista
@using PrimerMVC.Models.ViewModels @model AnimalesViewModel <ul> @for (int i = 0; i < Model.Animales.Count; i++) { <li> <span class="animal-id">Id: @(i + 1)</span>@Model.Animales[i]</li> <!-- Este viene de el ModelView--> } </ul>
-
- Ejemplo sencillo Modelo Controlador ViewModel
-
CONTROLLER
Llama a → dal
El URL quedará así → localhost/Carpeta/nombreController/Accion
ActionResult→ Se usa para generar el html que te devuelve el controlador. Index() Si no no va. Retorna una view() de la vista que se verá.RedirectToAction(accion, controlador)→ Sirve para que se mueva entre controladores o acciones, y elija la accion que le pasas de ese nuevo controlador- Params se pasan como string y en controlador, omitir “Controller”, lo pilla solo
- 3r Parametro → new {id = 2} Se pasa un parametro adicional que ira en la acción de ese controlador
-
Ejemplo completo Redirection
-
En el HomeController se crea la redireccion
public IActionResult AnimalDetail(int id) { return RedirectToAction("AnimalDetail", "Animal", new {id}); }
-
El form en Index.cshtml ira directamente a eso que hemos creado
<form asp-action="AnimalDetail" asp-controller="Home" method="post" style="display:inline;"> <button type="submit">
-
Se genera el AnimalController.cs donde se redirigia
public IActionResult AnimalDetail(int id) { AnimalDal dal = new AnimalDal(); AnimalDetailViewModel viewModel = new AnimalDetailViewModel(); viewModel.AnimalDetail = dal.GetById(id); return View(viewModel); }
-
La view Que estara en la carpeta Animal y se llamara AnimalDetail.cshtml
@model PrimerMVC.Models.ViewModels.AnimalDetailViewModel <!-- Esta vista sera donde le llega toda la info de el Animal Detail y se muestra--> <h1>Detalles del Animal</h1> <p>Id: @Model.AnimalDetail.IdAnimal</p> <p>Nombre: @Model.AnimalDetail.NombreAnimal</p> <p>Raza: @Model.AnimalDetail.TipoAnimal</p>
-
Importante→ No puede haber @Model en el Layout PADRE, ya que sino dara error en todos los componentes
Controlador nuevo → Agregar/Nuevo controlador en blanco
En C# Cuando haces {get, set} y usas esa propiedad, no hace falta llamar a un metodo que sea setNoseque, simplemente asignando objeto.Noseque = “algo” ya funcionaria
-
Ejemplo ENTERO Back Basico
-
Crear los Modelos que seran los objetos que se simulan las instamcias de las tablas.
-
Code
public class Animal { public int IdAnimal { get; set; } public string NombreAnimal { get; set; } public string Raza { get; set; } public int RazaAnimal { get; set; } public int RiTipoAnimal {get; set;} public DateTime? FechaNacimiento { get; set; } public TipoAnimal TipoAnimal { get; set; } }
-
-
DAL → Crear la clase que haga el Crud
-
+ Valores *(Select *)*→ Si se devuelve una lista, haremos un while en el DataReader, generando los objetos y añadiendolos a la lista.
-
1 Valor *(Select id)*→ Se puede hacer con el Reader (
if (reader.Read()) que busca la primera linea) - o se puede hacer con executeScalar y un objeto -
Code
public class AnimalDal { private string connectionString = ""; [Obsolete] public List<Animal> GetAll() { List<Animal> animales = new List<Animal>(); TipoAnimalDal tipoaAnimalDal = new TipoAnimalDal(); using (SqlConnection conn = new SqlConnection(connectionString)) { string sqlQuery = "SELECT * FROM Animal"; SqlCommand cmd = new SqlCommand(sqlQuery, conn); conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { Animal animal = new Animal() { IdAnimal = Convert.ToInt32(reader["id"]), NombreAnimal = reader["NombreAnimal"].ToString(), Raza = reader["Raza"]?.ToString(), RITipoAnimal = Convert.ToInt32(reader["RIdTipoAnimal"].ToString()), FechaNacimiento = reader["FechaNacimiento"] == DBNull.Value ? (DateTime?)null : Convert.ToDateTime(), TipoAnimal = tipoaAnimalDal.GetById(Convert.ToInt32(reader["RIdTipoAnimal"])), }; animales.Add(animal); } return new List<Animal>(); }
-
-
Controller
-
Asigna la info del DAL y la envia al ViewModel
-
Codigo
[Obsolete] public IActionResult Index() { AnimalDal dal = new AnimalDal(); AnimalesViewModel viw = new AnimalesViewModel(); viw.Animales = dal.GetAll(); return View(viw); }
-
-
ViewModel
- Solo se usa si cogemos info de +1 tabla
-
Index.cs.html
-
Donde Ira todo lo que se visualiza, Razor, Vista
-
Codigo ejemplo diferente
@using PrimerMVC.Models.ViewModels @model AnimalesViewModel @{ ViewData["Title"] = "Home Page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <ul> @for (int i = 0; i < Model.Animales.Count; i++) { <li> <span class="animal-id">Id: @(i + 1)</span>@Model.Animales[i]</li> <!-- Este viene de el ModelView--> } </ul> </div>
-
Ejemplo bueno
@using PrimerMVC.Models.ViewModels @model AnimalesViewModel @foreach(var animal in Model.Animales) { <li> <span class="animal-id">Id: @animal.IdAnimal</span>@animal.NombreAnimal</li> <!-- Este viene de el ModelView--> } </ul>
-
-
-
Compartir info vista-controlador, como LocalStorage pero de .NET
ViewData → Diccionario [key, value] Solicitud actual
Se suele usar para mensajes de error
ViewBag → Dinamico ViewBag.Mensaje Para mensajes de error
-
Controlador
viewModel.AnimalDetail = dal.GetById(id); if (viewModel.AnimalDetail == null) { ViewBag.NoAnimal = "No se ha encontrado este animal"; }
-
Vista
@{ var errorMessage = ViewBag.NoAnimal as string; } @if (!string.IsNullOrEmpty(errorMessage)) { <div class="alert alert-danger" role="alert"> @errorMessage </div> } else {Mostrar contenido normal}
Va mejor para recuperar strings
TempData → Desaparece cuando se ha consultado
Variables de sesion
HttpContext.Session(nombreVar, valor) -
-
ANOTACIONES
Estas anotaciones se añaden en el modelo y son atributos y funcionales que se aprovecharan al interactuar con este. Tambien se puede usar en un ViewModel.
[key]→ Declarar un atributo como PK del modelo[Required]→ Indica que el atributo es obligatorio, se añade un mensaje de error[StringLength]→ Especifica Limite caracteres atributo[Range]→ Numerico, que rango tiene que ser lo que entra[Display]→ Como se ve en la vista ese atributo?[DataType]→ Definimos el tipo de dato[EmailAdress]→ Que tenga formato de correo electronico[Compare]→ Para comprobar igualdad e.j. comparar ContraseñaPara añadir el span en form →
asp-validation-form=atributosi falla algoHay que añadir en la vista cshtml:
@section Scripts{ @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } }
-
Ejemplo modelo + vista
En la vista si no se cumplen las anotaciones del modelo, saldra el span
public class Animal { public int IdAnimal { get; set; } [Required(ErrorMessage = "El nombre del Animal es obligatorio.")] [StringLength(50, ErrorMessage = "No puede ser de mas de 50 caracteres.")] [Display(Name = "Nombre del Animal")] public string NombreAnimal { get; set; } [StringLength(50, ErrorMessage = "No puede ser de mas de 50 caracteres.")] [Display(Name = "Raza")] public string? Raza { get; set; } public int RITipoAnimal {get; set;} [Display(Name = "Fecha de Nacimiento")] [DataType(DataType.Date, ErrorMessage = "Debe ser una fecha valida.")] [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] public DateTime? FechaNacimiento { get; set; } public TipoAnimal TipoAnimal { get; set; } }
@using PrimerMVC.Models.ViewModels @model AddAnimalViewModel <form asp-action="AddAnimalBBDD" asp-controller="Animal" method="post" style="display: flex; flex-direction: column;" asp-antiforgery="true"> <label asp-for="animal.NombreAnimal">Nombre</label> <input asp-for="animal.NombreAnimal" type="text" value="" /> **<span asp-validation-for="animal.NombreAnimal"></span>** <form> @section Scripts{ @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } }
[ValidateAntiForgeryToken]→ para CSRF, valida que siempre se haga todo con token- Se añade la [] en el controlador
-
<form asp-action=”Accion” **asp-antiforgery=true /**>Para que funcione
Formulario Con ASP o sin ASP
Sin Asp, generamos un formulario normal con un boton submit. El controlador a donde se envia tendra que tener tantos parámetros como inputs había
Los valores se envian con el atributo del input name
-
Codigo Vista
@using PrimerMVC.Models.ViewModels @model AddAnimalViewModel @{ Animal animal; } <h1>Editar un Animal</h1> <form asp-action="AnimalUpdate" asp-controller="Animal" method="post" style="display: flex; flex-direction: column;"> <input type ="hidden" name="id" value="@Model.animal.IdAnimal" /> <label>Nombre</label> <input type="text" name="nombreAnimal" value="@Model.animal.NombreAnimal" /> <label>Raza</label> <input type="text" name="raza" value="@Model.animal.Raza" /> <label>Fecha de Nacimiento</label> <input type="date" name="fechaNacimiento" value="@Model.animal.FechaNacimiento" /> <label>Tipo Animal</label> <select name="idTipoAnimal"> <option disabled> Selecciona el tipo de animal</option> @foreach (var tipo in Model.TipoAnimales) { if (Model.animal.TipoAnimal == tipo) { <option selected value="@tipo.IdTipoAnimal">@tipo.TipoDescripcion </option> } else { <option value="@tipo.IdTipoAnimal">@tipo.TipoDescripcion </option> } } </select> <button type="submit" style="margin-top: 10px;">Agregar</button> </form>
Con asp, añadimos a los inputs
asp-for=”ElementViewmodel.Element.atribute”y eliminar el atributo nameDe esta manera lo que se recibirá en el controlador será por parametro el ViewModel y recuperaremos de ahí los objetos y atributos.
-
Codigo Vista
@using PrimerMVC.Models.ViewModels @model AddAnimalViewModel <h1>Añadir un Animal</h1> <form asp-action="AddAnimalBBDD" asp-controller="Animal" method="post" style="display: flex; flex-direction: column;" asp-antiforgery="true"> <label>Nombre</label> <input asp-for="animal.NombreAnimal" type="text" name="nombreAnimal" value="" /> <span asp-validation-for="animal.NombreAnimal"></span> <label>Raza</label> <input asp-for="animal.Raza" type="text" name="raza" value="" /> <span asp-validation-for="animal.Raza"></span> <label>Fecha de Nacimiento</label> <input asp-for="animal.FechaNacimiento" type="date" name="fechaNacimiento" value="" /> <span asp-validation-for="animal.FechaNacimiento"></span> <label>Tipo Animal</label> <select asp-for="animal.RITipoAnimal" name="idTipoAnimal"> <option disabled> Selecciona el tipo de animal</option> @foreach (var tipo in Model.TipoAnimales) { <option value="@tipo.IdTipoAnimal">@tipo.TipoDescripcion </option> } </select> <span asp-validation-for="animal.RITipoAnimal"></span> <button type="submit" style="margin-top: 10px;">Agregar</button> </form> @section Scripts{ @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } }
-
-
Login
-
Para comprobar que el modelo que llega sea correcto
Recordad hacer una acción de controlador para la vista y luego si recibe algo
if (ModelState.IsValid) // Verifica las validaciones del modelo, osea las anotaciones que pusimos en el LoginViewModel { if (model.Username == "admin" && model.Password == "password") { // Autenticacion exitosa return RedirectToAction("Home", "Index"); } ModelState.AddModelError("", "Usuario o contraseña incorrectos"); // Esto se mostrara en asp-validation-summary="All" }
-
Salt & Hash
Es el metodo de cifrado para guardar contraseñas de manera que solo se puede descifrar si contienes los 3 elementos. Los primeros dos se guardan en la bb dd y el tercero se introduce en el login
-
Clase para Crear & Verify Hash
namespace LoginMVC.Tools { public static class PasswordHelper { public static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt) { using(var hmac = new HMACSHA512()) { passwordSalt = hmac.Key; passwordHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password)); } } public static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt) { using(var hmac = new HMACSHA512()) { var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password)); return computedHash.SequenceEqual(storedHash); } }
-
Uso
-
Para configurar las variables de sesión hay crear un middleware, que sería un programa que se ejecuta entre servidor y cliente cuando se recibe una llamada http.
Para esto, se configura al inicio en Program.cs.
En program.cs preseteamos:
// Aqui añadimos la config de la variable de sesion para el Auth builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromDays(30); // Tiempo de expiracion options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); // Despues de crear app tmbn añadimos: app.UseSession(); // Declaramos que usaremos la sesion que hemos creado
En el AuthController
HttpContext.Session.SetString("Username", model.Username);
Despues en HomeController se podria hacer para usar la sesion que hemos seteado al iniciar
// Si estas logeado se guarda la sesion y podremos ver index, // sino, te redirije al login public IActionResult Index() { string username = HttpContext.Session.GetString("Username"); if (string.IsNullOrEmpty(username)) return RedirectToAction("Login", "Authentication"); return View(); }
-
HTTP Calls y Proyecto
GET
Cuando en un form lo hacemos a traves de get, si es por ejemplo search?title=Hola entonces si el modelView tiene un campo llamado title, ahi habra un Hola.
POST
HttpResponses
OK → simplemente en la view se hace un return ok(model);
Ordenar por LINQ
// Si se ha intorducido algo en Title, filtramos por titulo
if (model.Title != "" || model.Title != null)
{
books = books.Where(book => book.Title.Contains(model.Title, StringComparison.OrdinalIgnoreCase)).ToList();
}