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.
10 comentarios:
Muchas gracias. Muy útil.
Gracias Arturo por leer el blog :)
Muito legal, adicionei o blog no google reader o/
Gracias Cristian por leer el blog y por tus comentarios
saludos
Que pasa si uno ha modificado mucho el modelo del EF, y luego cambia algunas cosas en la base de datos, y tiene que hacer un Update Model From Database, todos estos cambios se conservan?
Gracias Anónimo por leer el blog. En este caso, yo recomiendo poner las relaciones modificadas en clases aparte, aprovechándonos del hecho de que las clases de las entidades son parciales, con esto no se altera el código agregado, solamente debes estar pendiente del generado
saludos
Buen post, me aclaró las dudas cuando tenemos de forma lógica varios objetos pero se deben almacenar en la misma tabla. Así se quita la mala costumbre de programar pensando en tablas.
Voy a leerme el de polimorfismo a ver como me va.
Esta muy buena esta caracteristica de EF. Te queria consultar como puedo hacer una GUI en WinForms con capa de presentacion (modelo MVP) para un ABM de entidades heredadas. Debo siempre trabajar a partir de la clase base no? En mi caso mi modelo tiene una Entidad base Persona y de ahi heredo por ej. un tipo Empleado y tambien Familiar. A su vez Familiar tambien se relaciona con Persona (para decir que es un familiar_de digamos).Muchas Gracias muy bueno el blog!
Hola Diego una pregunta rapida, sera posible usar entity framework cuando el modelo de datos no esta bien relacionado
Hola Diego una pregunta si tengo las entidades A1 y A2 que heredan de A, como podria hacer para que el objeto A1 se convierta en A2 o de A2 a A1, esto para conservar el id que se genera en la entidad A
Saludos.
Publicar un comentario