Tips para llevarse bien con Entity Framework I

Veremos varios consejos para llevarnos bien con esta herramienta y poder sacarle el jugo.

Rodríguez Patiño, Eduardo
2020-12-01 | 40,175 lecturas

Esta entrada requiere conocimientos previos con el Entity Framework

Comparto esta entrada donde dare ciertas pautas para aprender a sobrevivir y llevase con nuestro amigo el Entity Framework.

1- Cuando trabajamos un proyecto avanzado y conectamos a N base de datos la tarea se pone un poco más compleja.. Por lo tanto, mi solución en estos casos fue trabajar a punta de vistas (SQL Views) y cuando tengo que hacer un insert/update/delete declaro varias cadenas de conexión y veo con que contexto trabajar.

2- Si vas a iniciar un proyecto de cero te recomiendo previamente analizar y CONOCER las reglas de negocio para tu sistema. Asimimo, define las reglas de negocios y crea tus tablas con las siguientes pautas:

Nuestro primary key deben llamarse "id", ser numérico y asignarle la propiedad identity.

Ejem: tenemos la tabla Usuario, esta sería su estructura:

Usuario
id
int primary key identity
Nombre VARCHAR(20)
FechaNacimiento DateTime

De esta manera trabajamos los ID para nuestras tablas para que el EF lo reconozca por defecto. Si queremos hacer una relación hacia otra tabla, debemos asignar un campo de la siguiente manera Usuario_id. Por ende, etendiendo como EF maneja los ID podemos comenzar a crear todas nuestras tablas y saltarnos al paso 3.

3- Recomiendo instalar el EF Tools el cual existe para la versión 2012 y 2013 de nuestro visual studio. Con esto vamos a poder generar nuestras clases para trabajar con el EF pero usando código puro.

Instalamos el EF Tools, y en nuestra visual studio en el explorador de soluciones, le damos click derecho y agregar nuevo elemento, elegimos la opciòn que dice datos.

Image title

Elegimos ADO.NET Entity Data Model y la opción Code First, seteamos nuestra cadena de conexión y elegimos las tablas a mapear.

Esta herramienta me va de lujo, ya que me crea un modelo bastante limpio. Veamos un ejemplo:

namespace Data
{
    using System;
    using System.Data.Entity;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using Data.Entity;

    public partial class ColegioContext : DbContext
    {
        public ColegioContext()
            : base("name=ColegioContext")
        {
        }

        public virtual DbSet<Curso> Curso { get; set; }
        public virtual DbSet<Rol> Rol { get; set; }
        public virtual DbSet<Usuario> Usuario { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {

        }
    }
}

Así obtenemos una clase Contexto bastante limpia y lista para comenzar a trabajar.

4- La jerarquía que uso para mis proyectos que usan EFPersonalmente yo dentro de mi solución creo un nuevo proyecto para agregar nuestras entidades y accesos a datos (consultas SQL).
La jerarquía que uso es la siguiente:

Data
-- Entity
----- Rol
----- Curso
----- Usuario
-- Model
----- UsuarioModel
----- RolModel
ColegioContext.cs

Entity: guardo mis entidades  que hacen referencia a las tablas.
Model: hago las consultas a la base de datos con cierta lógica de negocio.

El objetivo de esto es encapsular las reglas de negocio de nuestro proyecto en el modelo y evitar tener que hacerlo en el controlador. ¿Que pasa si queremos replicar la misma lógica de un controlador?, ¿Copiamos todo nuestro código de nuevo?

5- Para actualizar mis entidades que me genera el EF Tools, lo que hago es crear una nueva carpeta y recrear todas las entidades de esta manera las remplazo por las anteriores.

5- La cadena de conexión siempre va en el webconfig, mi clase Context al incializar el constructor hara referencia al connection string definido en el webconfig.

6- Cuando quiero agregar un campo adicional que no correspende a nuestra clase de Entidad, simplemente agregamos la etiqueta [NotMapped] arriba de nuestro atributo. De esta manera nuestro EF no lo va a considerar en el momento de inserción o actualización.

7- Como hago un listado con el EF

public List<Usuario> Listar()
{
    var usuarios = new List<Usuario>();

    using (var context = new ColegioContext())
    {
        try
        {
            usuarios = context.Usuario
                            .Include( x => x.Rol)
                            .ToList();
        }
        catch (Exception e)
        {

        }
    }

    return usuarios;
}

8- Como hago un insert con el EF

public void Registrar(Usuario usuario)
{
    using (var context = new ColegioContext())
    {
        try
        {
            context.Usuario.Add(usuario);
            context.SaveChanges();
        }
        catch (Exception e)
        {

        }
    }
}

9- Como hago un update con el EF, como les dige el EF sabra que existe un atributo llamado ID y por lo tanto sabra que es el PK de nuestra entidad y armar el query del update correctamente usando como WHERE a nuestro atributo ID, si usan el sql profiler se daran cuenta.

public void Actualizar(Usuario usuario)
{
    using (var context = new ColegioContext())
    {
        try
        {
            context.Entry(usuario).State = EntityState.Modified;
            context.SaveChanges();
        }
        catch (Exception e)
        {

        }
    }
}

10- Como elimino un registro, nuevamente el EF sabra que el ID es el criterio tomado para eliminar un registro determinado.

public void Eliminar(Usuario usuario)
{
    using (var context = new ColegioContext())
    {
        try
        {
            context.Entry(usuario).State = EntityState.Deleted;
            context.SaveChanges();
        }
        catch (Exception e)
        {

        }
    }
}

11- Si quiero traer un solo registro lo que debemos hacer es lo siguiente:

public Usuario Obtener(int id)
{
    var usuario = new Usuario();

    using (var context = new ColegioContext())
    {
        try
        {
            usuario = context.Usuario
                            .Where(x => x.id == id)
                            .SingleOrDefault();
        }
        catch (Exception e)
        {

        }
    }

    return usuario;
}

12- Si queremos eliminar ciertos registros en base a ciertas condiciones, lo que el EF dice es que traigamos esos registros a eliminar primero y luego pasarselo para hacer el DELETE, lo que yo digo es lo siguiente

context.Database.ExecuteSqlCommand("DELETE FROM Usuario WHERE id IN (@p0, @p1)", 1, 4);

Donde ejecuto en duro una consulta SQL y le paso parametros, estos parametros deben empezar con p0, p1 asi sucesivamente, y el siguiente parametro del ExecuteSqlCommand son los valores enviar de esta manera evitamos un SQL Injection

13- Como ejecuto un Storeprocedure, supongamos que tenemos un query bastante complicado entonces le dejamos la tarea a nuestros procedures y lo que hacemos es decirle al EF en que entidad quiero que mapee el resultado y que procedure debe ejecutar. Ejemplo:

var Usuarios = context.Database.SqlQuery<Usuario>("USP_PROCEDURE_COMPLICADO_USUARIO @p0", 1).ToList();

De esta manera le digo que el resultado a obtener que debe coincidir con mi entidad Usuario y quiero que sea una lista, es decir un List.

14- Transacciones con EF, en este enlace esta bien explicado http://msdn.microsoft.com/en-us/data/dn456843.aspx, de todas formas te copio el código de un ejemplo

using (var ctx = new DBXContext())
{
    using (var ctxTrans = ctx.Database.BeginTransaction())
    {
        try{
            // Mi hermoso código aquí
            ctxTrans.Commit(); // Aprobado
        }catch (Exception){
            ctxTrans.Rollback(); // Desaprobado
        }
    }
}

15- Muchas veces queremos actualizar ciertos campos dejando a un lado algunos, para ignorar dichos campos hacemos lo siguiente:

// Dentro del contexto seteamos a false las 2 propiedades a continuación:
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;

var eCS = ctx.Entry(cs);
eCS.State = EntityState.Modified;

// Quitamos los campos que no queremos actualizar
eCS.Property(x => x.Camion_id).IsModified = false;
eCS.Property(x => x.PESO_BRUTO).IsModified = false;
eCS.Property(x => x.VOLUMEN).IsModified = false;

ctx.SaveChanges();

Actualizado 28 de mayo, 2015.