[OPINION]Del Cliente al Desarrollador, pasando por el JP, y los marrones.

Antes de nada, quiero dejar claro que este POST está totalmente basado en mis Opiniones y Experiencias.

En cuantas ocasiones nos habremos encontrado con que llega nuestro Jefe y nos dice:

“Tengo un proyectito para dos semanitas muy facilito…”

“Tengo un proyectito que nada, son tres pantallas….”

Esto no viene a ser una crítica a los Jefes, viene a significar que parece que jugamos al “Teléfono escacharrado”  como cuando éramos pequeños.

El cliente dice quiero: “a”

Nuestro Jefe, que está curtido en mil proyectos, dice: "El cliente quiere ‘A’”.

Desde hace tiempo, siempre que alguien me dice: “Tengo un caramelito de proyecto…”, me digo para mi mismo: “Esto huele a marrón :-(".

Una vez que has hablado con tu Jefe, llega el momento de la verdad y juntarse con el cliente, para ver realmente que va a ser ese “A” que te ha trasmitido tu Jefe.

Estás en una sala con tu Jefe, esperando que llegue el Cliente. Cuando llega, viene preparado, viene con material (si tienes mucha suerte te lo habrán enviado si no…) para expresar sus ideas.

Después de un buen rato, en el que prestas mucha atención – puesto que como “Desarrolladores” que somos, generalmente cambiamos de cliente como de… camisa – debido a que no conoces ni su negocio, ni lo que realmente quiere.

Comienzas a pensar: “Mi jefe me dijo ‘A’, pero yo mas bien estoy viendo algo de ‘A+b+C’”

Cuando el cliente termina de contar ‘todo’ lo que quiere, llega tu turno de preguntas, ya sean mas o menos técnicas, y le empiezas a decir lo típico:

– “¿Qué tipo de acceso se necesita?”

– “¿Hay algún tipo de excepción al caso ‘D’?”…

Bien, después de unas largas horas de reunión donde se han podido fijar algunos conceptos, descubres que verdaderamente “A” es “Super A con pintas de B + C + D + E”.

En fin, vuelves a pensar: “Si ya decía yo que esto pintaba a marrón…”.

La situación ideal, para evitar sorpresas de este tipo, sería que los clientes se parasen detenidamente a pensar que es lo que realmente necesitan y tratar de definir un conjunto de primeras especificaciones, para ahorrar disgustos más que nada, pero esta situación no se si la viviremos alguna vez.

[Evento] Charla sobre WinForms para AndorraDotNet (15/04/2011)

Hola a todos.

 

Como reza el título, gracias a Lluis Franco, voy a subir al Grupo de Usuarios de Andorra “AndorraDotNet” ha dar una charlita sobre Winforms el día 15 de Abril entre las 18:00 y las 20:00.

Lo que principalmente voy a contar será acerca de:

  • Controles Personalizados.
  • Métodos Extensores.
  • Plantillas.

Si estás por Andorra y te apetece una charla, serás bien recibido 😉

Saludos!

[EF + Oracle] Consulta de los datos (II)

Prologo

En el capítulo anterior, realizamos una primera toma de contacto con la consulta de Datos con Linq –To Entities.

Continuación

Al igual que se puede realizar en una consulta SQL, con Linq to Entities disponemos la posibilidad de utilizar la palabra reservada “group”.

Esta sentencia nos va a permitir definir agrupaciones del conjunto de entidades devueltas por nuestra consulta.

Sintaxis SQL:

   1: using (OracleConenction con = new OracleConenction("MyConnection"))

   2: {

   3:     using (OracleCommand cmd=new OracleCommand(@"SELECT ID_PEDIDO,SUM(UNIDADES) 

   4:                                                 FROM DETALLES_PEDIDO

   5:                                                 GROUP BY ID_PEDIDO",con))

   6:     {

   7:  

   8:     }           

   9: }

Sintaxis Linq-EF:

   1: var query = from DETALLE_PEDIDO detalle in context.DETALLE_PEDIDO 

   2:             group detalle by detalle.ID_PEDIDO into g

   3:             select new  {g.Key,Suma = g.Sum(a=>a.UNIDADES)};

En la parte de la select hago uso de la palabra reservada new, para crear un tipo de dato anónimo, con las propiedades que quiero utilizar.

Expresión Lambda:

   1: var query = context.DETALLE_PEDIDO.GroupBy(detalle => detalle.ID_PEDIDO).Select(detalle => 

   2:                 new { 

   3:                     detalle.Key, 

   4:                     Unidades = detalle.Sum(suma => suma.UNIDADES) 

   5:                     }).ToList();

Este ejemplo de agrupación ha sido con una única columna, pero puede darse la situación de tener que agrupar por más de una columna. De nuevo, gracias a los tipos anonimos, podremos logar acometer nuestro objetivo. (El ejemplo es un poco tonto, pero sirve para ver la sintaxis)

Sintaxis SQL:

   1: using (OracleConenction con = new OracleConenction("MyConnection"))

   2: {

   3:      using (OracleCommand cmd = new OracleCommand(@"SELECT ID_PEDIDO,ID_PRODUCTO,SUM(UNIDADES) 

   4:                                                     FROM DETALLES_PEDIDO

   5:                                                     GROUP BY ID_PEDIDO,ID_PRODUCTO", con))

   6:     {

   7:     }

   8: }    

Sintaxis Linq-EF:

   1: var query = from DETALLE_PEDIDO detalle in context.DETALLE_PEDIDO 

   2:             group detalle by new {detalle.ID_PEDIDO,detalle.ID_PRODUCTO} into g

   3:             select new { g.Key.ID_PEDIDO,

   4:                          g.Key.ID_PRODUCTO,

   5:                          Suma = g.Sum(suma=>suma.UNIDADES)};

Expresión Lambda:

   1: var query = context.DETALLE_PEDIDO.GroupBy(detalle => new 

   2:             { detalle.ID_PEDIDO, detalle.ID_PRODUCTO }).

   3:             Select(detalle => new

   4:             {

   5:                 detalle.Key.ID_PEDIDO ,

   6:                 detalle.Key.ID_PRODUCTO ,

   7:                 Unidades = detalle.Sum(suma => suma.UNIDADES)

   8:             }).ToList();

 

En el próximo capítulo veremos la sintaxis necesaria para realizar uniones entre distintas tablas con EF.

[EF + Oracle] Consulta de los datos (I).

Prologo

Hasta el momento, hemos visto un acercamiento a trabajar con Entity Framework y Oracle viendo:

  1. Introducción
  2. Entidades
  3. El Contexto
  4. Inserción de Datos (1 y 2)
  5. Actualización y Borrado de Datos

Durante este y algunos de los siguientes capítulos, vamos a trabajar sobre la consulta de datos con Entity Framework

Introducción a las Consultas de Datos

Por lo general, a la hora de hacer consultas a la Base de Datos, generábamos una clase donde construíamos una o varias sentencias SQL, y a través del los objetos Command, las ejecutábamos contra la conexión existente y devolvíamos los datos en un DataTable o en un DataReader y los utilizábamos como necesitásemos.

Para consultar la BD en Entity Framework, se va a utilizar LINQ – To – Entities. En lugar de construir una sentencia SQL que acceda directamente a la Base de Datos, se va a llevar a cabo una consulta sobre el modelo de Entity Framework en la Entidad (Tabla) sobre la que se desea obtener información.

Internamente, la consulta LINQ que se va a generar va a ser transformada a lenguaje SQL entendible por el motor de Base de Datos, y va a devolver un conjunto de resultados sobre dicha consulta.

En estos posts no voy a entrar a decir como se realiza una consulta SQL, ya que hay mucha información relativa a eso, y en mi propio blog he puesto ya algunos ejemplos.

 

Creación de una consulta sencilla en EF

El orden de las consultas de EF difiere con respecto de una consulta SQL.

En primer lugar necesitamos definir el Origen de los Datos, es decir, la Entidad que queremos consultar (FROM).

Después, se podrán indicar:

  1. Condiciones de filtrado a través de la palabra reservada Where.
  2. Forma de Agrupación de los datos a través de la palabra Reservada Group by
  3. Forma de Ordenación de los datos a través de la palabra reservada order by.

Y por último, será necesario que indiquemos, a través de la palabra reservada Select, las propiedades que queremos visualizar.

Para ver esto, vamos a hacer un pequeño ejemplo:

Sintaxis SQL:

   1: using (OracleConnection connection=new OracleConnection("MyConnection"))

   2: {

   3:     using (OracleCommand command = 

   4:             new OracleCommand("Select * from Empleados",connection))

   5:     {

   6:         connection.Open();

   7:  

   8:     }

   9: }

 

Sintaxis EF:

   1: var query = from EMPLEADOS employee in ent.EMPLEADOS

   2:                         select employee;

 

Con ambas consultas vamos a obtener el mismo resultado, todos los empleados de la tabla / entidad.

Para realizar esta consulta, realmente no es necesario hacerlo con esta sintaxis de EF, se puede realizar directamente accediendo al ObjectSet Empleados del contexto, obteniendo el mismo resultado.

   1: var query = ent.Empleados;

De la misma manera que en SQL podemos realizar filtrado de registros a visualizar a través de la palabra reservada Where, en EF también podemos utilizarlo:

Sintaxis SQL:


   1: using (OracleConnection connection = new OracleConnection("MyConnection"))

   2: {

   3:     using (OracleCommand command =

   4:       new OracleCommand("select * from empleados where nombre like '%j%'", connection))

   5:      {

   6:          connection.Open();

   7:      }

   8: }

Sintaxis EF:

   1: var query = from Empleados emp in ent.Empleados

   2: where emp.Nombre.Contains("c")

   3: select emp;

Expresión Lambda (Método Extensor Where)

   1: var query = ent.Empleados.Where(empleado => empleado.Nombre.Contains("c"));

 

En los próximos capítulos vamos a entrar más en profundidad en la consulta de Datos utilizando Linq-To-Entities, viendo las palabras reservadas que nos falta.

EF, Oracle y SP1 de VS2010

Este es un post cortito, para informar algo que me ha parecido curioso y que he visto en la web de Oracle.

Si tenéis Visual Studio 2010, y estáis trasteando con Entity Framework para Oracle con el driver ODP.NET, si instaláis el SP1, os vais a encontrar con esto:

Al crear o editar un modelo de Entity Framework el IDE se queda colgado.

Fuente: http://www.oracle.com/technetwork/topics/dotnet/tech-info/default-338300.html#mozTocId468690

[EF + Oracle] Actualización y Borrado de Datos

Prologo

En los capítulos anteriores hemos visto como insertar datos a través de EF, sin secuencias y posteriormente con secuencias. En este capitulo vamos a hablar de la actualización y el borrado de datos.

Actualización de Datos

La modificación de los datos asociados (propiedades) de una Entidad, es una operación muy común y sencilla.

Antes de llevar a cabo la modificación de los valores de una Entidad, podemos determinar el estado de la misma, y observaremos que EntityState tiene un valor EntityState.Unchanged.

Para modificar los datos basta con modificar una Entidad existente. En el ejemplo utilizo un método “ObtenerEmpleadoAModificar(2)” que me va a devolver un empleado válido:

   1: EMPLEADOS emp=ObtenerEmpleadoAModificar(2);

   2: emp.NOMBRE="a";

   3: emp.TELEFONO="2";

   4: emp.EMAIL="aa";

Una vez realizadas todas las modificaciones de un empleado, vamos a volver a comprobar el valor de EntityState, en este caso va a tener el valor EntityState.Modified.

Para persistir estos cambios a la Base de Datos, vamos a invocar a la función SaveChanges, de nuestro contexto.

   1: contexto.SaveChanges();

Si volvemos a revisar la propiedad EntityState, obervaremos que su valor ha pasado a ser EntityState.Unchanged.

 

Borrado de Datos

Otra operación muy sencilla, es el borrado de una entidad.

El primer paso para poder eliminar una Entidad, es seleccionar la que queremos borrar, e invocar al método DeleteObject del conjunto al que pertenece dicha entidad.

   1: CLIENTES  clienteSeleccionado=ObtenerCliente(15);

   2: contexto.CLIENTES.DeleteObject(clienteSeleccionado);

Antes de invocar a la función la propiedad EntityState va a tener el valor EntityState.Unchanged, y en el momento de la eliminación va a pasar a tener el valor EntityState.Deleted.

Para confirmar el borrado de la Entidad de la base de datos, es necesario como siempre, que invoquemos la función SaveChanges.

Peculiaridades del Borrado

Entity Framework permite tanto actualizaciones como borrados en cascada, aunque las actualizaciones, personalmente no las he visto en muchos sitios.

¿Qué es un Borrado en Cascada?

Un borrado en cascada es una acción que permite la eliminación de los entidades de detalle relacionadas con la Entidad que estamos eliminando.

El borrado en cascada se puede habilitar a la hora de definir las relaciones de la Base de datos.

Gracias al diseñador de Entity Framework, sin necesidad de habilitarlo en la Base de Datos, podemos habilitar el borrado en cascada para una relación determinada.

Ejemplo:

Dada una relación (1-N) Entre clientes y Pedidos

La situación Normal sería no poder eliminar aquellos Clientes, que tengan datos en la Tabla Cabecera_Pedido.

Si seleccionamos la relación (la flecha 1 –> *), y pulsamos con el botón secundario del raton, y propiedades, podremos observar el siguiente listado:

Este listado muestra las propiedades de la relación, indicando la tabla Maestra (Clientes) y la tabla detalle (Cabecera_Pedido).

La propiedad End1 OnDelete nos va a indicar que accion vamos a realizar en el caso de borrar un dato en la tabla Maestra. Existen dos opciones:

– None: No va a realizar ninguna accion en la tabla detalle, por lo tanto si una entidad maestra tiene datos relacionados no se va a poder eliminar.

– Cascade: Va a realizar un borrado de los datos de detalle, antes de realizar el borrado de la Entidad Maestra.

Si habilitamos el borrado en cascada de una relación, e invocamos a la función DeleteObject del conjunto, podremos observar que todas las entidades de Detalle (de la relación indicada) presentan el valor EntityState.Deleted en la propiedad EntityState.

Del mismo modo que en el borrado, inserción o actualización, hasta que no se invoque al método SaveChanges, los cambios no van a ser confirmados en la Base de Datos.

Nota: He explicado el borrado en cascada para que lo conozcáis y sepáis como se utiliza, pero personalmente, a no ser que se traten de errores, no me gusta utilizar el borrado en cascada.

Conclusiones

En este episodio hemos visto como llevar a cabo modificaciones y borrado de entidades, y el borrado en cascada.

En próximos capítulos entraremos a ver las consultas sobre las Entidades, y sobre el propio generador de EF.

[EF + Oracle] Insertando en la Base de Datos (Secuencias) (2/2)

Prologo

En el episodio anterior hemos visto una forma de crear registros con EF, ahora vamos a ver peculiaridades de ORACLE.

ORACLE

Una característica que posee SQL Server con respecto de Oracle es “Identity”.

Para todos aquellos que no han trabajado con SQL Server, esta propiedad, que aplica a columnas del Tipo Integer permite definirlas como Autoincreméntales, de esa manera se van a rellenar de forma automática, sin tener que especificar la sentencia de inserción a la Base de Datos.

En Entity Framework contra SQL Server, las propiedades que son de este tipo, no se tienen que rellenar tampoco, porque se auto rellenan en SQL Server.

En Oracle, no se dispone directamente de está característica, pero se puede lograr algo parecido.

Secuencias

Las secuencias son objetos de la Base de Datos, que nos permiten generar auto incrementos, pero que no se asocian directamente a una Tabla de la BD.

   1: CREATE SEQUENCE nombre_secuencia

   2: INCREMENT BY numero_incremento 

   3: START WITH numero_por_el_que_empezara 

   4: MAXVALUE valor_maximo | NOMAXVALUE 

   5: MINVALUE valor_minimo | NOMINVALUE 

   6: CYCLE | NOCYCLE 

   7: ORDER | NOORDER

   8:  

La sintaxis para definir una secuencia en Oracle es la que se indica arriba, se define con un nombre, un valor mínimo y un valor máximo y el valor en el que empieza.

¿Como se obtiene el valor de la secuencia?

Para poder obtener el próximo valor de la serie, es necesario ejecutar una consulta SQL:

   1: SELECT nb_secuencia.Nextval 

   2: From Dual

Ya que no se puede asociar de forma directa una secuencia a una columna de la Tabla, se puede optar por utilizar un Trigger Antes de la inserción del Registro y ejecutar la sentencia, o, una opción que se me ha ocurrido:

Puesto que el modelo de EF importa solo los objetos de Tipo Tabla o Procedimientos Almacenados / Funciones, he decidido crear un método extensor:

 

   1: public static class EFSequence 

   2:     {

   3:         public static int GetNextValue(this ObjectContext contexto, string SequenceName) 

   4:         {

   5:             string Connection = ConfigurationManager.ConnectionStrings["JTorrecillaEntities2"].ConnectionString;

   6:             Connection=Connection.Substring(Connection.IndexOf(@"connection string=")+19);

   7:             Connection = Connection.Remove(Connection.Length - 1, 1);

   8:             using (IDbConnection con = new Oracle.DataAccess.Client.OracleConnection(Connection))

   9:             {

  10:                 using (IDbCommand cmd = con.CreateCommand())

  11:                 {

  12:                     con.Open();

  13:                     cmd.CommandText = String.Format("Select {0}.nextval from DUAL", SequenceName);

  14:                     return Convert.ToInt32(cmd.ExecuteScalar());

  15:                 }

  16:             }

  17:  

  18:          }

  19:     }

Este método extensor del ObjectContext,  va a realizar la consulta arriba indicada con el nombre de la Secuencia indicada en el parámetro “SequenceName”. Lee la cadena de conexión generada en el fichero de configuración a la hora de crear el modelo de EF, y le quita la información de metadata sobrante. Devolviendo el siguiente valor disponible de la secuencia.

El valor de la secuencia es único, por lo tanto, a la hora de tener usuarios concurrentes al crear nuestras claves con un valor de la secuencia no se van a duplicar.

Esta implementación es propia, es decir, se que hay otras formas y se que no es la más correcta de hacerla, si encuentro una mejor o se me ocurre otra la posteare.

PD: Para poder usar el método extensor, es necesario que en el proyecto referencia a la DLL de Oracle, que encontrareis en el directorio BIN. Escoged la DLL para .NET 4.0

[EF + Oracle] Insertando en la Base de Datos (1/2)

Prologo

Continuando con la serie de Entity Framework (I ,II y III) en este capítulo vamos a ver como crear registros en la Base de Datos a Través de Entity Framework.

Inserción de Datos

Tal y como hablaba en el 2º post, una entidad se va a corresponder con un registro de la Base de Datos, y cada una de las propiedades con una columna de la Tabla a la que representa la Entidad.

Para comenzar, será necesario que creemos una variable del tipo de Entidad que queremos insertar en la Base de Datos:

   1: EMPLEADOS empleado = new EMPLEADOS();

Como, también comente en el post anterior, existe la posibilidad de utilizar el método estático definido por VS en cada Entidad:

Una vez que hayamos creado el objeto de la entidad, podremos acceder a sus propiedades, para rellenarlas como una clase normal:

 

   1: empleado.NOMBRE = "Javier Torrecilla";

 

Después de rellenar las propiedades de nuestra Entidad, será necesario que lo agreguemos al ObjectSet de nuestro ObjectContext:

   1: enti.EMPLEADOS.AddObject(empleado);

o

   1: enti.AddToEMPLEADOS(empleado);

Ambos métodos van a realizar la misma acción, generar una inserción para la BD.

¿Hemos terminado?

No.

Toda Entidad, posee una propiedad “EntityState”, del tipo enumeración EntityState, que presenta los siguientes tipos:

  • Detached: Este estado  indica que la Entidad ha sido creada, pero no se ha añadido a la base de Datos.
  • Unchanged: Este estado indica que la Entidad no tiene cambios con respecto de consulta o desde la última vez que se actualizo la BD.
  • Added: Indica que se ha agregado al ObjectSet, pero todavía no se ha enviado a la Base de Datos.
  • Deleted: Indica que el objeto se ha borrado del contexto, pero todavía no de la BD.
  • Modified: Indica que el objeto tiene modificaciones pendientes de guardar en la BD.

Vamos a ver los cambios que se dan en la Propiedad durante los pasos de creación de un Registro y lo vamos a relacionar con su paso a la BD:

  1. Creación de la Entidad y asignación de las propiedades: EntityState=EntityState.Detached;
  2. Agregar el objeto al ObjectSet: La propiedad va a pasar a tener el valor EntityState.Added. Esto todavía no indica que se haya creado el registro en la Base de Datos.
  3. Guardar los Datos:

    Para poder guardar los datos en la base de Datos será necesario invocar a la función “SaveChanges()” de nuestro contexto. Una vez invocada la función, el valor de la Propiedad EntityState será EntityState.Unchanged.

 

¿Qué realiza la función SaveChanges?

Esta función se encarga de sincronizar y enviar todos los cambios pendientes de realizar a la BD.

Se van a agregar, modificar y eliminar todos aquellos Entidades, cuyas propiedad EntityState, tengan un valor Added, Deleted o Modified.

Una vez finalizado el proceso, aquellas entidades con la propiedad en valor Added o Modified, van a pasar a tener un estado “Unchanged”, y aquellas entidades en estado “Deleted”, van a pasar a un estado “Detached”.

[EF + Oracle] Object Context

Prologo

Continuando con la serie de Entity Framework (I y II) en este capítulo vamos a ver que es el Object Context.

¿Qué es Object Context?

Es la clase encargada de la gestión de la conexión con la Base de Datos y la gestión de las distintas Entidades de nuestro Modelo.

A la hora de generar el modelo de EF, ya explique, Visual Studio genera una clase para cada Entidad. Además de las Entidades, genera un objeto de Contexto.

Esta clase hereda de la Clase ObjectContext, la cual nos provee de lo siguiente:

  • Una conexión con la Base de Datos.
  • Métodos para añadir, modificar y borrar datos de la Base de Datos.
  • Conjuntos de las distintas entidades de nuestro modelo.
  • Estado de los registros cacheados (o Entidades con cambios pendientes)

 

Esta clase va a contar con una función, para cada entidad, del tipo “AddTo{ENTIDAD}({Tipo_Entidad} valor)”, la cual va a permitir agregar el parámetro “valor” al conjunto (Object Set) de la Entidad indicada por el método.

Por otro lado, va a contar una propiedad, para cada entidad, del tipo “ObjectSet<TEntity> Entidad” que va a almacenar el conjunto de datos de la entidad. Está propiedad se va a rellenar a través de la función: CreateObjectSet<TEntity> de la clase base (ObjectContext).

¿Qué es un ObjectSet?(Datos sacados de mi antiguo Blog)

Es la clase que nos permite manejar el conjunto de Entidades por un tipo dado.
Hereda de la clase genérica ObjectQuery, la cual genera una colección de resultados a través de una consulta. La consulta y la conexión van a venir indicados a través del ObjectContext.
Además también implementa las siguientes Interfaces:

  • ObjectQuery<TEntity>: genera una colección de resultados a través de una consulta. La consulta y la conexión van a venir indicados a través del ObjectContext.
  • IObjectSet<TEntity>: genera las cabeceras de los métodos que nos permiten modificar el conjunto de datos de la entidad.
  • IQueryAble<TEntity>: nos va a facilitar la funcionalidad para poder consultar los datos del objeto.
  • IEnumerable<TEntity>: nos va a permitir generar un enumerador de los datos de la entidad.
  • IQueryAble: nos va a facilitar la funcionalidad para poder consultar los datos del objeto.
  • IEnumerable: nos va a permitir generar un enumerador de los datos de la entidad.

 

Con lo indicado anteriormente, podemos decir, que un ObjectSet de una Entidad nos va a devolver todos los registros de una tabla, nos va a permitir agregar, modificar o borrar los datos de un registro, nos va a permitir hacer filtros, y listarlos.

Las consultas de datos las veremos en próximos capítulos.

 

Una propiedad importante del Contexto es “LazyLoadingEnabled”. Esta propiedad, de tipo booleana, permite indicar si la carga de los datos se realiza de forma diferida o no. ¿Qué significa esto?, que el objeto no se crea y consulta hasta que no es necesario.

 

Conclusiones:

Con  este post hemos visto que es el contexto generado por VS, algunas de sus características y donde vemos los datos de las entidades.

En los próximos episodios veremos, como consultar los ObjectSets, y como realizar operaciones CRUD.