Skip to content

Notion Documentation

Daniel Álvarez del Reguero edited this page Feb 1, 2025 · 1 revision

Bootcamp .NET

Propietario: daniel alvarez Etiquetas: Guías y procesos GitHub: https://github.com/danipoal/Bootcamp.NET

C#

Sintaxis Básica

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

https://www.notion.so/icons/info-alternate_pink.svg

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

Arrays - Colecciones

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 valor

Archivos

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.

HashTablekey,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: 5

Herencia

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);
			}
		}
}
https://www.notion.so/icons/info-alternate_pink.svg

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 Null

linq-cheatsheet.pdf

Funciones con genéricos

funcion T buscar() where T : Persona

LINQ

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

WinForms

C4.1.1 - Aplicaciones de Escritorio.pdf

Items usuales

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.DialogAbre 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

Layout

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
    1. Indicar que el valor que contendra el Picker sea nada

      this.dateTimePicker1.CustomFormat = " ";  
      this.dateTimePicker1.Format = DateTimePickerFormat.Custom;
    2. Creamos un evento que se ejecute cuando el valor cambia

      dateTimePicker1.ValueChanged += new EventHandler (dateTimePicker1_ValueChanged);

    3. 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

BD

Curso SQL Ciberanium

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
    1. Ir a la BD dentro de el smss

    2. Botón derecho → Tasks/Import data/Microsoft Access

    3. Seleccionar Archivo .mdb y Next la opción SQL provider

      Seleccionar la  bd en la que quieres introducir

      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 Pedidos Si quieres mes sería MONTH(), DAY()…

        https://www.notion.so/icons/info-alternate_pink.svg

        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

  • 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;
      https://www.notion.so/icons/info-alternate_orange.svg

      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;

      image.png

      • 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;
      https://www.notion.so/icons/info-alternate_green.svg

      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
    • 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 deleted para verlo
        • deleted.Nombre_Columna
  • 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.2 - Diseño logico.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

    C3.3.2 - Tipos de Join y Group By (1).pdf

    C3.3.5 - DDL CREATE TABLE (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.
https://www.notion.so/icons/info-alternate_pink.svg

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ógicoFísico (DB Administrator)

Diagrama E-R

Cardinalidad

image.png

image.png

  • 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

Normalización

  • DuplicadosIntentar 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.
  • 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

    https://www.notion.so/icons/info-alternate_orange.svg

    → 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

    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.

DDL

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

DML

  • Inserción de SUBQUERRYS

    Para crear la tabla SELECT INTO(Se introducen valores de la tabla referenciada) y luego INSERT 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%'
  • 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_id por 2 valores

    https://www.notion.so/icons/info-alternate_orange.svg

    El 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 GROUP

    Deja 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.

    image.png

    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

Front

tablas

table-rows que contiene tabla-data Atributos

colspan 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)

BACK

Conexión a BD, DAL y manipulación sencilla

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.show el 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 .
      • Si quieres que te devuelva el ID de lo que insertas → ExecuteScalar y 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}");
              }
          }
        https://www.notion.so/icons/info-alternate_orange.svg

        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.

    https://www.notion.so/icons/info-alternate_orange.svg

    Diferencia .AddWithValue y .Add en 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

    1. Execute Scalar, como query pero devuelve un object que casteamos a int que es el id.
    2. Se recupera el id, y se lo asignamos a el objeto job que hemos insertado.

ASP.NET

WebForms

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)

    1. Plantilla app Web ASP.NET NETframework
    2. 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

MVC

  • 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 javascript

    TagHelper → 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
      1. 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"
                };
            }
        }
      2. 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);
        }
      3. 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>
  • 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
      1. En el HomeController se crea la redireccion

        public IActionResult AnimalDetail(int id)
        {        
        	return RedirectToAction("AnimalDetail", "Animal", new {id});
        }
      2. 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">
      3. 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);
        }
      4. 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>
    https://www.notion.so/icons/info-alternate_orange.svg

    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

    https://www.notion.so/icons/info-alternate_orange.svg

    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

      AnimalesTablas.sql

      1. 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; }
          
          }
      2. 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>();
              }
      3. 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);
                  }
      4. ViewModel

        • Solo se usa si cogemos info de +1 tabla
      5. 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ña

    https://www.notion.so/icons/info-alternate_orange.svg

    Para añadir el span en form → asp-validation-form=atributo si falla algo

    Hay 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
    https://www.notion.so/icons/info-alternate_orange.svg

    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 name

    De 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

    Configuración de la Sesion

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

}