Cuando se utiliza el EntityFramework normalmente generamos el modelo en la capa de acceso a datos y procedemos a trabajar directamente con las entidades generadas desde la base de datos. Sin embargo, al estar trabajando con Entidades, estamos trabajando directamente con el estado del objeto de negocios generado a partir de la tabla asociada, con lo cual podemos aprovecharnos de todas las bondades del mundo de la orientación a objetos. Quizás la más obvia es la herencia, en donde podemos crear nuestras entidades sobre modelos de herencia para crear un esquema de entidades de trabajo más simple y más comprensible.
Ejemplo
Para ver la herencia funcionando con el Entity Framework vamos a crear un ejemplo en donde vamos a tener dos tipos de empleado: El empleado de planta y el empleado contratista o consultor. El esquema de base de datos sobre el cual vamos a basar este ejemplo es el siguiente:
Nótese que en este esquema vamos a tener una tabla para manejar empleados, esta tabla tiene una asociación con una tabla empresa; tanto el empleado de planta como el empleado contratista deben de tener una empresa asociada { en el empleado de planta porque puede ser que la empresa sea un conglomerado de empresas y hay que identificar cual empresa es la que lo tiene en planilla}. Además, podemos ver que en la tabla empleado existe el campo salario y el campo costo por hora. El salario es el asignado al empleado de planta ya que la empresa si conoce cuanto se le paga; sin embargo, al empleado contratisa no se conoce cuanto le paga la empresa contratista por lo tanto se le asigna el costo por hora que cobra la empresa contratista por cada empleado.
Para crear la aplicación procedemos a crear un proyecto en WPF de la siguiente forma:
Observemos que esta vez creamos el UI en WPF sin embargo la solución solamente se llama Herencia.EF. El siguiente paso es crear una librería para la capa de acceso a datos – para ver como se crea ver este post –, luego procedemos a agregar el esquema de base de datos antes creado utilizando un modelo del Entity Framework.
En nuestro caso el esquema generado es el siguiente:
Agregando la Herencia
Ahora vamos a proceder a agregar la herencia de entidades en nuestro modelo. Vamos inicialmente a crear dos entidades más: el empleado contratista y el empleado de planta. Para esto procedemos a dar clic derecho sobre el modelo generado por el Entity Framework y seleccionamos la opción de agregar Entidad.
Procedemos primero a agregar el empleado contratista
Luego procedemos a agregar el empleado de planta.
Luego de esto el diagrama del modelo del Entity Framework nos debería quedar así:
Luego procedemos a cortar las propiedades específicas para cada empleado de la clase base para especializar cada una de las entidades.
El siguiente paso es crear los mapas para que el Entity Framework tenga noción de como funciona la herencia especificada. En este paso, tenemos que crear los mapas necesarios para indicarle al Entity Framework en que momento se utiliza una instancia de EmpleadoDePlanta y en que circunstancia un EmpleadoContratista. Primero vamos a seleccionar EmpleadoDePlanta, luego vamos a agregar un mapeo en la ventana de Detalles de los mapas; para lograr esto, una vez seleccionado la entidadEmpleadoDePlanta procedemos a agregar un nuevo mapa justo debajo de la definición de la tabla, en este nuevo mapa agregamos la condición del mapa, la cual sería que cuando el campo TipoEmpleado sea igual a “empleado” entonces proceda con una instancia de EmpleadoDePlanta.
Al igual que hicimos con el EmpleadoDePlanta, ahora procedemos a crear un mapeo para el empleado contratista pero esta vez el mapeo de la columna la hacemos a través de la propiedad CostoXHora
Una vez agregado estos mapeos de herencia todavía nos falta reparar unos errores que se dan porque cambiamos de una forma no tan inferible el comportamiento de estas entidades. El primero error es el siguiente:
Esto se da porque a la hora de crear la instancia de la entidad y basados en la condición de mapeo para la columna TipoEmpleado, no hemos definido que instancia se debe de crear cuando no se tiene un valor en TipoEmpleado, o mejor dicho, no hemos definido cuando se debe crear una instancia de Empleado. Hay dos formas de repararlo; la primera creando un valor para cuando no se quiere un empleado específico y la segunda crear el tipo Empleado como abstracto para que no se pueda instanciar, solamente se pueda a heredar, y en nuestro caso vamos a utilizar la segunda opción. Para esto procedemos a marcar la clase empleado, vamos a las propiedades y ahi buscamos la propiedad Abstract y le establecemos el valor en true.
Si volvemos a compilar obtenemos otro error, el cual es un poco más ambiguo.
En este caso, el error se da porque la variable TipoEmpleado se mapea automáticamente a la hora de crear las instancias de las clases que heredan de empleado y por lo tanto no debe de estar disponible para ser modificada, por esta razón lo único que debemos hacer en este caso es remover la propiedad TipoEmpleado. El nuevo esquema es el siguiente:
Ahora vamos a proceder a utilizar nuestro modelo. Como hemos hecho en post anteriores acerca de aplicaciones n-layer con el entity framework procedemos a crear una capa de lógica de negocios desde donde estaremos creando nuestros métodos para obtener empleados de planta y empleados Contratistas.
public class EmpleadoBL
{
Ejemplos_BlogEntities1 _contexto = new Ejemplos_BlogEntities1();
public List<EmpleadoDePlanta> ObtenerEmpleados( )
{
var empleadosDePlanta = _contexto.Empleado.OfType<EmpleadoDePlanta>();
return empleadosDePlanta.ToList();
}
public List<EmpleadoContratista> ObtenerEmpleadosContratistas( )
{
var empleadosContratistas = _contexto.Empleado.OfType<EmpleadoContratista>();
return empleadosContratistas.ToList();
}
}
Es de resaltar el uso del método de extensión OfType a través del cual le solicitamos explícitamente al Entity Framework cual tipo es el que queremos y por lo tanto el debe mapear. Seguidamente procedemos a dibujar la pantalla en WPF a través de la cual vamos a desplegar los datos.
Esta pantalla aunque muy sencilla nos servirá para ilustrar el uso de los métodos anteriores y la respectiva herencia en el Entity Framework. El código en cada uno de los RadioButton es el siguiente:
private void rdRegular_Checked( object sender, RoutedEventArgs e )
{
if (dgEmpleaddos != null)
{
EmpleadoBL empleadoBL = new EmpleadoBL();
dgEmpleaddos.ItemsSource = empleadoBL.ObtenerEmpleados();
}
}
private void rdContratista_Checked( object sender, RoutedEventArgs e )
{
if (dgEmpleaddos != null)
{
EmpleadoBL empleadoBL = new EmpleadoBL();
dgEmpleaddos.ItemsSource = empleadoBL.ObtenerEmpleadosContratistas();
}
}
Si ejecutamos este código, nos vamos a dar cuenta que el Entity Framework resuelve correctamente nuestras consultas de acuerdo al tipo solicitado en cada método invocado.
Aquí estamos solicitando ver los empleados de planta y como se aprecia en la foto el primer campo que nos aparece es el salario.
En la siguiente imagen estamos solicitando ver los contratistas y por lo tanto nos aparece el costo por hora de cada empleado.