Jornada de Acceso a Datos en el MUG

por Daniel Laco  22. agosto 2011

El 31 de Agosto estaré participando de una jornada completa sobre temas de Acceso a Datos.

Se desarrollará desde las 9 hasta las 18 en la UADE (Univ. Argentina de la Empresa). 

Salón Auditorio - Lima 717, puerta M, Ciudad de Buenos Aires

En evento está referido a tecnologías, herramientas y técnicas sobre el manejo de datos en programación. Se verán temas como ORM, NoSql, La Nube, etc.

Se pueden registrar aquí

 

HorarioTemaOrador
09:00Keynote – Apertura del eventoMartín Salías
09:10Preview de SQL Server 2011 (Denali)Maxi Acotto
10:10SQL AzureGuadalupe Casuso
11:00Coffee break
11:20¿Por Qué Entity Framework?Daniel Laco
12:10Mobile Data AccessCarlos Perez
13:00Almuerzo Libre
15:20oData / Web APIPablo Cibraro
15:20Web Storage en HTML5Rodolfo Finochietti
16:10Coffee break
16:20Bases de datos NoSQLJohnny Halife
17:10Persistencia con NHibernate 3.2.0Fabio Maulo
18:00Cierre

Nos vemos en el evento !

 

Tags: , ,

ADO.NET | Entity Framework

Self-Tracking Entities en Entity Framework 4

por emmanuel  24. agosto 2010

Introducción: tipos de entidades en Entity Framework

Desde la salida de Entity Framework, al generar modelos de entidades, las clases generadas derivan de EntityObject.
Con la salida de la versión 4 de Entity Framework, se incorpora soporte para seleccionar el tipo de entidad de la cual van a derivar nuestras entidades de negocio: a los clásicos EntityObject se agregan como novedad POCO, POCO Proxies y Self-Tracking entities.
Antes de desarrollar las entidades de tipo Self-Tracking (el objetivo de este artículo), es conveniente dar un panorama de estos diferentes tipos de entidades, para poder decidir cual utilizar, dependiendo de la arquitectura de la aplicación a realizar:

  • EntityObject

Por defecto, las herramientas de ADO.NET Entity Data Model generan tipos de entidades que derivan de EntityObject. En este caso, el ObjectContext administra las relaciones entre los objetos, mantiene el historial de los cambios que ocurren (Change-Tracking) y soporta Lazy Loading.

Sin embargo, este tipo de entidades dependen fuertemente del Entity Framework. Si se desea trabajar con arquitecturas que no conocen la forma de persistencia (por ejemplo: TDD, Test-Driven Development), lo más deseable es utilizar entidades de tipo POCO o POCO Proxy.

  • POCO

Entity Framework permite utilizar objetos del dominio existentes junto con el modelo de datos, sin hacer cambios a las clases de datos. Estas clases POCO ("Plain-Old" CLR Objects), son conocidas como objetos que ignoran la persistencia y soportan las mismas funcionalidades de Query, Insert, Update y Delete que los objetos EntityObject.

Al trabajar con entidades POCO, los cambios que se realicen al grafo de objetos no son mantenidos automáticamente por Entity Framework a medida que ocurren, sino que se utiliza un mecanismo de snapshots para detectarlos: se debe llamar a DetectChanges para sincronizar el ObjectContext con el grafo actualizado (por defecto, el ObjectContext llama a este método antes de grabar los datos).

Este mecanismo utiliza mas memoria que el anterior y puede afectar la performance, especialmente si la aplicación requiere la detección de cambios frecuentemente. Para poder tener una notificación instantánea de los cambios, se debe activar la creación de objetos Change-Tracking Proxy, y para activar Lazy Loading se debe activar la creación de Proxies de Lazy Loading.

  • POCO Proxy

Se debe utilizar en los casos en los que se requiera detección de cambios instantánea y Lazy Loading. Al utilizarlo, se tiene la misma funcionalidad que con entidades tipo EntityObject, pero con las clases del dominio separadas del Entity Framework. Los proxies se crean en tiempo de ejecución, lo que implica que las entidades generadas difieren del tipo POCO, introduciendo algunas complicaciones con la serialización. Por otra parte, la creación de proxies consume mas recursos que los objetos POCO.

  • Self-Tracking Entities

Los tres tipos definidos anteriormente funcionan correctamente en aplicaciones donde los objetos pueden ser agregados (Attach) al ObjectContext que maneja el historial de cambios. Sin embargo, cuando se desea transferir un grafo de entidades a una capa donde el ObjectContext no está disponible, se debe decidir como mantener el historial de cambios y reportar esos cambios de vuelta al ObjectContext (por ejemplo: arquitectura en capas, ambientes desconectados, arquitecturas SOA, etc.).

A partir de la versión 4 de Entity Framework, las entidades del tipo Self-Tracking pueden grabar cambios a las propiedades escalares, complejas o de navegación. Este tipo de entidades no dependen del Entity Framework, y son generadas con el template de ADO.NET Self-Tracking Entity Generator.

Self-Tracking Entities

En arquitecturas en capas, el ObjectContext puede no estar disponible en la capa que modifica las entidades. A partir de Visual Studio 2010 (con Entity Framework 4), está disponible el template ADO.NET Self-Tracking Entity Generator. Este template genera dos archivos .tt (text template):

El archivo <nombreModelo>.tt genera los tipos de entidades y una clase helper que contiene la lógica de mantenimiento de cambios, mas los métodos de extensión que permiten establecer el estado de las entidades.

El archivo <nombreModelo>.Context.tt genera un ObjectContext tipado y una clase de extensión que contiene los métodos ApplyChanges para las clases ObjectContext y ObjectSet. Estos métodos examinan la información del historial de cambios para inferir las operaciones a realizar para grabar los cambios en la base de datos.

Para acceder al template se debe hacer click derecho sobre la superficie del diseñador de entidades, y seleccionar “Add Code Generation Item”:

SelfTracking001

 

En la ventana que aparece, seleccionar “ADO.NET Self-Tracking Entity Generator”:

SelfTracking002

Al presionar “Add”, se ejecutarán los templates que crearán las clases necesarias, las cuales contendrán los métodos de extensión necesarios para trabajar con Self-Tracking:

SelfTracking003

Métodos de extensión de Self-Tracking Entities

  • StartTracking

Este método se utiliza para comenzar el Change-Tracking (rastrear cualquier cambio que ocurra en la entidad). Esto incluye propiedades escalares, colecciones y referencias a otras entidades. Las entidades de tipo Self-Tracking inician el Change-Tracking automáticamente cuando son deserializadas en un cliente a través de WCF. También se activa para nuevas entidades creadas en los siguientes escenarios:

  1. Una relación es creada entre la nueva entidad y una entidad que actualmente tiene Change-Tracking activado.
  2. Se llama al método MarkAs o AcceptChanges en una entidad.

 

  • StopTracking

Este método finaliza el Change-Tracking en una entidad.

  • MarkAs

Todos los métodos que comienzan con “MarkAs” activan el Change-Tracking. Estos métodos permiten cambiar el estado de una entidad a Added, Modified, Deleted, o Unchanged, y además retornan la misma entidad a la cual son aplicados, con el estado modificado:

MarkAsAdded cambia el estado de una entidad a Added. Las nuevas entidades Self-Tracking son creadas en este estado y con Change-Tracking desactivado.

MarkAsDeleted cambia el estado de una entidad a Deleted.

MarkAsModified cambia el estado de una entidad a Modified. Este estado también se obtiene al cambiar el valor de una propiedad en una entidad con Change-Tracking activado.

MarkAsUnchanged cambia el estado de una entidad a Unchanged. También se obtiene este estado al llamar al método AcceptChanges.

  • AcceptChanges

Este método elimina la información de Change-Tracking para una entidad y coloca el estado en Unchanged (es decir, la entidad acepta los cambios que se le realizaron).

Métodos de extensión de ObjectContext

  • ApplyChanges

Examina la información del historial de cambios contenida en el grafo de entidades e infiere el conjunto de operaciones que deben realizarse para reflejar los cambios en la base de datos. Hay dos métodos ApplyChanges, uno para el ObjectContext y otro para el ObjectSet.

Consideraciones para trabajar con entidades Self-Tracking

Finalmente, para cerrar, les dejo algunas consideraciones a tener muy en cuenta antes de utilizar este tipo de entidades:

  • Al enviar un grafo modificado a un servicio, y luego intentar continuar trabajando con el el grafo modificado en el cliente, se debe iterar manualmente por el grafo en el cliente y llamar a AcceptChanges en cada objeto para resetear el Change-Tracking.

  • Las entidades Self-Tracking no permiten realizar Lazy Loading.

  • La serialización Binaria y la serialización a objetos de administración de estados ASP.NET no es soportada por el código generado por los templates de ADO.NET Self-Tracking Entity Generator, para soportala se debe agregar el código necesario al template.

Fuentes:

Tags: ,

ADO.NET | Entity Framework | Visual Studio

Cuál es la mejor forma de realizar procesos batch con Entity Framework?

por Daniel Laco  16. abril 2010

Es muy común que en las aplicaciones sea necesario realizar procesos de actualizaciones masivas. Siempre está la tentación de usar EF para hacer estos procesos, ya que es muy fácil buscar y actualizar registros. Pero en el caso de EF el costo que se paga por toda la infraestructura que tiene es muy alto.

En el caso de procesos masivos, si hay que actualizar o borrar un registro, primero hay que traerlo (esto implica que EF mantenga el tracking con el ObjectStateManager) posteriormente hacer la actualización o borrado y por último realizar la actualización con el ObjectContext.

Resumiento, para realizar procesos batch lo mejor es NO USAR Entity Framework !!

Pero que opciones tengo entonces?

Voy a mostrar 2 alternativas de las muchas que hay, simulando que hay que leer un archivo .TXT de longitud fija  y posteriormente hay que realizar una actualización de miles de registros en una tabla de la base de datos.

El escenario es que recibo un archivo con códigos de productos de la empresa y códigos de productos de proveedores externos. El proceso que hay que realizar es: leer el archivo y actualizar los códigos de de los proveedores externos en cada registro de los productos de la empresa.

Para esto usaremos como ayuda la excelente libreria FileHelpers realizada por Marcos Meli

El formato en que viene el archivo es el siguiente:

 

/// <summary>
/// Archivo de Unión de Códigos de Productos de la Empresa y Proveedores
/// </summary>
 
[FixedLengthRecord(FixedMode.AllowLessChars)]
public class UnionProductos
{
    [FieldFixedLength(7)]
    public int EmpresaCodigo;
 
    [FieldFixedLength(7)]
    public string Proveedor1Codigo;
 
    [FieldFixedLength(7)]
    public int Proveedor2Codigo;
 
}

 

El proceso de lectura con FileHelpers:

FileHelperEngine engine = new FileHelperEngine(typeof(UnionProductos));
UnionProductos[] UnionLeido = engine.ReadFile(nombreArchivo) as UnionProductos[];
 
 

Opción 1

Recorrer el array de Productos y ejecutar un Store Procedure con la actualización correspondiente:

 

string stringDeConexion = "XXXXXXXXXXXXXXXX";
using (SqlConnection conn = new SqlConnection(stringDeConexion))
{
    conn.Open();
    SqlCommand cmd = new SqlCommand("nombreStore", conn);
    cmd.Parameters.Add("@empresaCodigo", SqlDbType.Int);
    cmd.Parameters.Add("@proveedor1Codigo", SqlDbType.VarChar);
    cmd.Parameters.Add("@proveedor2Codigo", SqlDbType.Int);
 
 
    foreach (UnionProductos producto in UnionLeido)
    {
        cmd.Parameters[0].Value = producto.EmpresaCodigo;
        cmd.Parameters[1].Value = producto.Proveedor1Codigo;
        cmd.Parameters[2].Value = producto.Proveedor2Codigo;
 
        cmd.ExecuteNonQuery();
 
    }
}

 

Por supuesto el Store hace algo asi como:

UPDATE Productos 
SET Proveedor1Codigo = @proveedor1Codigo, 
    Proveedor2Codigo = @proveedor2Codigo
WHERE Productos.Codigo = @empresaCodigo

 

Opción 2

Esta es la mas performante de las 3 opciones. El único problema es que solo es posible en SQL Server 2008.

Está implementada utilizando una Tabla como Parámetro y realizando toda la actualización mediante una sentencia SQL.

Veamos como hacelo:

Se crea un tipo de dato Table en SQLServer

CREATE TYPE UnionProductosTbl AS TABLE 
(
    EmpresaCodigo int,
    Proveedor1Codigo varchar(7),
    Proveedor2Codigo int
)

 

Se crea el Procedimiento Almacenado usando ese tipo como parámetro:

CREATE PROCEDURE ActualizarCodigosProveedores
    @unionProductosTbl dbo.UnionProductosTbl READONLY
AS
BEGIN
 
    UPDATE Productos p
    SET p.Proveedor1Codigo = tbl.Proveedor1Codigo,
    p.Proveedor2Codigo = tbl.Proveedor2Codigo
    FROM Productos
    INNER JOIN @unionProductosTbl tbl ON p.Codigo = tbl.empresaCodigo
    
END

 

Y el proceso en el código:

//Lectura del Archivo
               FileHelperEngine engine = new FileHelperEngine(typeof(UnionProductos));
               //Devuelve como DataTable
               DataTable unionLeidoDT = engine.ReadFileAsDT(nombreArchivo);
 
               //El proceso de actualización
               string stringDeConexion = "XXXXXXXXXXXXXXXX";
               using (SqlConnection conn = new SqlConnection(stringDeConexion))
               {
                   conn.Open();
                   SqlCommand cmd = new SqlCommand("nombreStore", conn);
                   //Se define un parámetro de tipo Structured para que reciba un DataTable
                   SqlParameter par = cmd.Parameters.Add("@unionProductosTbl", 
                       SqlDbType.Structured);
                   par.Value = unionLeidoDT;
                   cmd.ExecuteNonQuery();
               }
               
 

Realizando el proceso con 17.000 registros los resultados fueron los siguientes (los tiempos son orientativos):

Opción Tiempo

Utilizando EF

8 minutos

Utilizando ADO.NET nativo procesando registro a registro con un Store Procedure

4 minutos

Utilizando un Store Procedure en SQL 2008 con una tabla como parámetro

4 segundos !!

 

Para finalizar, la opción de realizar el proceso batch usando una tabla como parámetro de un Store es la mejor opción si la prioridad es la performance de la solución.

Tags: ,

ADO.NET | Entity Framework | SQL Server

Extensibilidad en el Entity Framework Designer en VS2010

por Daniel Laco  23. marzo 2010

 

Una de las cosas mas intersantes que tiene el diseñador del EF en Visual Studio 2010 es la posiblidad de extender las funcionalidades mediante el agregado de nuevas propiedades a una entidad, o la posibilidad de poder interceptar el momento de grabar un archivo edmx, u otras opciones mas.

Esto es muy útil para cuando hay equipos de desarrollo extendidos, o varios proveedores diferentes trabajando en una empresa  y se quiere mantener una uniformidad al momento de escribir código.

Asi que mediante un ejemplo sencillo explicaremos los pasos necesarios para poder implementar una propiedad en las entidades que nos permita definir si una entidad es auditada o no.

Mostraremos como agregar esa propiedad y como utilizarla posteriomente en nuestro código.

Aclaración: todo lo mostrado en este artículo, está realizado sobre la RC de VS2010.

Como paso siguiente, manos a la obra!!

El equipo de ADO.NET publicó en CodePlex el ADO.NET Entity Data Model Designer Extension Starter Kit que nos permite hacer mucho mas fácil la tarea, y ya tiene varias opciones configuradas por default.

Podemos por ejemplo: 

      • Que el ADO.NET Entity Data Model Wizard agregue anotaciones personalizadas en cada tipo de entidad. El fundamento del tema lo encontramos en un ar tículo del blog de ADO.NET referido a diseño en http://blogs.msdn.com/efdesign/archive/2008/08/12/structural-annotations-one-pager.aspx (en inglés)
      • Que el ADO.NET Entity Data Model Wizard agregue anotaciones personalizadas durante las actualizaciones en cada entidad que se agregue al modelo conceptual.
      • Que el ADO.NET Entity Data Model Wizard agregue anotaciones personalizadas cuando las entidades son seleccionadas en el Designer o en el Model Browser.
      • También se puede extender el modo en se que cargan y graban los archivos .admx.
      • O permitir que el Diseñador grabe o carge archivos en un formato personalizado.

 

Paso 1: Instalar la extensión que se baja desde CodePlex

ExtensionManager

Paso 2: Crear el proyecto.

CrearProyecto

Paso 3: Una vez que tenemos el proyecto creado, podemos hacer las modificaciones que nos interesan. En este caso vamos a crear una propiedad para cada Entidad que nos permita habilitar o deshabilitar la auditoría. Creamos entonces una clase AuditarProperty:

using System;
using System.Linq;
using System.Xml.Linq;
using System.ComponentModel;
using Microsoft.Data.Entity.Design.Extensibility;
 
namespace EFEjemploExtension
{
    /// <summary>
    /// </summary>
    class AuditarProperty
    {
        internal static readonly string _namespace = "http://schemas.vemn.com/EFExtensions";
        internal static XName _xnMyNamespace = XName.Get("AuditarProperty", _namespace);
        internal const string _category = "Extensiones";
 
        private XElement _parent;
        private PropertyExtensionContext _context;
 
        public AuditarProperty(XElement parent, PropertyExtensionContext context)
        {
            _context = context;
            _parent = parent;
        }
 
        // Esta propiedad This property is saved in the conceptual content of an .edmx document in the following format:
        // <EntityType>
        //  <!-- other entity properties -->
        //  <MyNewProperty xmlns="http://schemas.vemn.com/MyNewProperty">True</MyNewProperty>
        // </EntityType>
        [DisplayName("Auditar Entidad")]
        [Description("Configura si la entidad es Auditable")]
        [Category(AuditarProperty._category)]
        [DefaultValue(false)]
        public bool AuditarEntidad
        {
            get
            {
                bool propertyValue = false;
                if (_parent.HasElements)
                {
                    XElement lastChild = _parent.Elements().Where<XElement>(element => element != null && element.Name == AuditarProperty._xnMyNamespace).LastOrDefault();
                    if (lastChild != null)
                    {
 
                        bool boolValue = false;
                        if (Boolean.TryParse(lastChild.Value.Trim(), out boolValue))
                        {
                            propertyValue = boolValue;
                        }
                    }
                }
                return propertyValue;
            }
 
            set
            {
                bool propertyValue = value;
 
 
                using (EntityDesignerChangeScope scope = _context.CreateChangeScope("Set AuditarEntidad"))
                {
                    if (_parent.HasElements)
                    {
                        XElement lastChild = _parent.Elements().Where<XElement>(element => element != null && element.Name == AuditarProperty._xnMyNamespace).LastOrDefault();
                        if (lastChild != null)
                        {
 
                            lastChild.SetValue(propertyValue.ToString());
                        }
                        else
                        {
                            _parent.Elements().Last().AddAfterSelf(new XElement(_xnMyNamespace, propertyValue.ToString()));
                        }
                    }
                    else
                    {
                        _parent.Add(new XElement(_xnMyNamespace, propertyValue.ToString()));
                    }
  scope.Complete();
                }
            }
        }
    }
}

 

Paso 4: Creamos el Factory.

using System.Xml.Linq;
using System.ComponentModel.Composition;
using Microsoft.Data.Entity.Design.Extensibility;
 
namespace EFEjemploExtension
{
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Export(typeof(IEntityDesignerExtendedProperty))]
    [EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType)]
    class AuditarPropertyFactory : IEntityDesignerExtendedProperty
    {
        /// <summary>
        /// </summary>
        /// <param name="element"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public object CreateProperty(XElement element, PropertyExtensionContext context)
        {
            return new AuditarProperty(element, context);
        }
    }
}

 

Paso 5: Una vez que hemos terminado, se compila y queda el arc hivo .vsix para ser in stalado en Visual Studio. En el Extension Manager veremos algo asi:

ExtensionInstalada>

Paso 6: Ya tenemos diponible la propiedad en el Diseñador de EF. Cuando agreguemos nuevas tablas o cuando se haga una actualización, las entidades tendrán ahora una nueva propiedad. Si seleccionamos una entidad veremos algo como:

AuditorPropiedad

 Paso 7: Por último, unos extension methods para poder consultar la Metadata del modelo que  nos permita obtener el valor de la propiedad:

 

public static class EFExtension
{
    /// <summary>
    /// Retorna el valor de una propiedad generada en la extensión del Diseñador del Entity Framework
    /// </summary>
    /// <typeparam name="T">Entidad para obtener la propiedad</typeparam>
    /// <param name="workspace"></param>
    /// <param name="propertyName">Ejemplo: http://schemas.vemn.com/EFExtensions:AuditarProperty</param>
    /// <returns></returns>
    public static bool GetExtentionPropertyAsBoolean<T>(this MetadataWorkspace workspace, string propertyName)
    {
        return (GetExtentionPropertyInternal<T>(workspace,propertyName).ToString().ToLower() == "true") ;   
    }
    /// <summary>
    /// Retorna el valor de una propiedad generada en la extensión del Diseñador del Entity Framework
    /// </summary>
    /// <typeparam name="T">Entidad para obtener la propiedad</typeparam>
    /// <param name="workspace"></param>
    /// <param name="propertyName">Ejemplo: http://schemas.vemn.com/EFExtensions:AuditarProperty</param>
    /// <returns></returns>
    public static string GetExtentionPropertyAsString<T>(this MetadataWorkspace workspace, string propertyName)
    {
        return GetExtentionPropertyInternal<T>(workspace, propertyName).ToString();
    }
 
    /// <summary>
    /// Retorna el valor de una propiedad generada en la extensión del Diseñador del Entity Framework
    /// </summary>
    /// <typeparam name="T">Entidad para obtener la propiedad</typeparam>
    /// <param name="workspace"></param>
    /// <param name="propertyName">Ejemplo: http://schemas.vemn.com/EFExtensions:AuditarProperty</param>
    /// <returns></returns>
    public static int  GetExtentionPropertyAsInt<T>(this MetadataWorkspace workspace, string propertyName)
    {
        return Convert.ToInt32(GetExtentionPropertyInternal<T>(workspace, propertyName));
    }
    /// <summary>
    /// Retorna el valor de una propiedad generada en la extensión del Diseñador del Entity Framework
    /// </summary>
    /// <typeparam name="T">Entidad para obtener la propiedad</typeparam>
    /// <param name="workspace"></param>
    /// <param name="propertyName">Ejemplo: http://schemas.vemn.com/EFExtensions:AuditarProperty</param>
    /// <returns></returns>
    public static object GetExtentionPropertyAsObject<T>(this MetadataWorkspace workspace, string propertyName)
    {
        return GetExtentionPropertyInternal<T>(workspace, propertyName);
    }
    /// <summary>
    /// Retorna el valor de una propiedad generada en la extensión del Diseñador del Entity Framework
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="workspace"></param>
    /// <param name="propertyName">Ejemplo: http://schemas.vemn.com/EFExtensions:AuditarProperty</param>
    /// <returns></returns>
    private static object GetExtentionPropertyInternal<T>(MetadataWorkspace workspace, string propertyName)
    {
        StructuralType objectSpaceType;
        workspace.LoadFromAssembly(typeof(T).Assembly);
        if (!workspace.TryGetItem<StructuralType>(typeof(T).FullName, DataSpace.OSpace, out objectSpaceType))
        {
            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "No se puede encontrar este tipo de datos en la Metadata", typeof(T)));
        }
        StructuralType edmType = workspace.GetEdmSpaceType(objectSpaceType);
 
        MetadataProperty mp = edmType.MetadataProperties.Where(x => x.Name == propertyName).Single();
        XElement xc = (XElement)mp.Value;
        return xc.Value;
    }
 
}

 

La forma de utilizar esta propiedad en nuestro codigo es:

NorthwindEntities ctx = new NorthwindEntities();
bool audita = ctx.MetadataWorkspace.GetExtentionPropertyAsBoolean<Customers>("http://schemas.vemn.com/EFExtensions:AuditarProperty");
//Hago algo con la auditoria

 

De esta forma, hemos visto como de manera relativamente sencilla se puede extender el Entity Designer y de que manera nos puede ayudar al momento de estandarizar configuraciones en las entidades.

Por supuesto que la cantidad de escenarios e ideas posibles con esta funcionalidad son muchas como pueden ser:

  • Revisión o Comenarios sobre los datos.
  • Seguridad en los Datos.
  • Agregado de Atributos del CLR
  • Validaciones de Anotaciones.
  • etc.
  • etc.

 

Aqui pueden bajar el código de ejemplo utilizado en el artículo.

 

 

 

 

Tags: , ,

ADO.NET | Entity Framework | ORM | Visual Studio

Que hay de nuevo en VS2010?

por Daniel Laco  4. marzo 2010

Ya se viene la liberación de la versión final de Visual Studio 2010 y .NET 4.0 y uno siempre quiere tener una vista rápida de los cambios, agregados, etc.

En http://msdn.microsoft.com/en-us/library/bb386063(VS.100).aspx pueden encontrar un listado de todos los temas nuevos de esta plataforma.

 

Tags: , , , ,

.NET | ADO.NET | ASP.NET | Entity Framework | Visual Studio | WCF | WinForms

Sintaxis diferentes para consultas en LINQ to Entities

por Gustavo Lombardo  4. febrero 2010

Hoy en día la mayor parte de las aplicaciones se desarrollan para que accedan a los datos de las bases interactuando con los mismos ya que se encuentran representados en un formato relacional (modelo relacional). Entity Framework nos permite trabajar con datos en forma de objetos y propiedades específicas del dominio sin tener que pensar en las tablas de las bases de datos o columnas en las que se almacenan estos datos. LINQ (Language-Integrated Query) nos facilita la vida a la hora de formular consultas en el código de las aplicaciones para interactuar con la base de datos, sin tener que usar un lenguaje de consulta independiente. A través de la infraestructura de Entity Framework, ADO.NET  muestra una vista conceptual común de los datos, como objetos del entorno .NET. Esto hace que la capa de datos sea compatible con LINQ. Esta tecnología, LINQ (LINQ to Entities), nos permite escribir consultas flexibles mediante el uso de operadores de consulta estándar y de expresiones LINQ en el entorno de desarrollo. Las consultas se expresan en el propio lenguaje de programación y no como literales de consulta incrustados en el código permitiendo que el compilador detecte errores de sintaxis en tiempo de compilación.

Una operación de consulta LINQ consta de tres acciones: obtener el origen o los orígenes de datos, crear la consulta y luego ejecutarla. Las instancias de la clase ObjectQuery, que implementa la interfaz genérica IQueryable, actúan como origen de datos para las consultas LINQ to Entities. La clase ObjectQuery genérica representa una consulta que devuelve una instancia o colección de entidades tipadas. Primero debemos crear una instancia de ObjectContext, que es la clase principal para interactuar con un Entity Data Model (EDM) como objetos de CLR (Common Language Runtime). Luego en la consulta especificamos exactamente la información que deseamos recuperar del origen de datos. Una vez creada se debe ejecutar.

Las consultas de LINQ to Entities se pueden formular en dos sintaxis diferentes:

 

  • Sintaxis de expresiones de consulta
  • Sintaxis de consultas basadas en métodos

 

La sintaxis de expresiones de consulta consta de un conjunto de cláusulas escritas en una sintaxis declarativa similar a Transact-SQL. Al usar la sintaxis de consulta, se pueden realizar operaciones complejas de filtrado, clasificación y agrupación en orígenes de datos con una cantidad mínima de código. En el siguiente ejemplo se muestra la operación de consulta completa que incluye la creación de un origen de datos, la definición de la expresión de consulta y la ejecución de la consulta en una instrucción forech:

 

class LINQQueryExpressions
{
    static void Main()
    {
        // Especificar origen de datos.
        int[] numeros = new int[] { 97, 92, 81, 60 };
 
        // Definir la consulta mediante la sintaxis de expresiones.
        IEnumerable<int> listaNumeros =
        from nro in numeros
        where nro > 80
        select nro;
 
        // Ejecutar la consulta.
        foreach (int i in listaNumeros)
        {
            Console.Write(i + " ");
        }            
    }
}
// Salida: 97 92 81

 

Todas las variables utilizadas con este tipo de sintaxis tienen establecimiento inflexible de tipos, aunque no es necesario que proporcionemos el tipo explícitamente ya que el compilador puede deducirlo. Debido a que .NET CLR no reconoce la sintaxis de expresiones de consulta por sí mismo, en tiempo de compilación las expresiones de consulta se convierten en elementos que CLR reconoce: las llamadas a métodos. Estos métodos se conocen como operadores de consulta estándar y tienen nombres como Where, Select, GroupBy, Join, Max, Average, etc. Este tipo de sintaxis no es más que una secuencia de llamadas directas a los métodos de operador de LINQ a las que le debemos pasar como parámetros expresiones lambda. En el siguiente ejemplo use el Select para devolver todas las filas de Empleados que cumplan con la condición  de tener 33 años y mostrar sus nombres.

 

using (EmpresaSAEntities data= new EmpresaSAEntities())
{
    IQueryable<string> nombreEmpleados = data.EmpleadosSet
        .Where(e=> e.Edad == 33)
        .Select(p => p.Nombre);
 
    Console.WriteLine("Nombre Empleados:");
    foreach (var nombre in nombreEmpleados)
    {
        Console.WriteLine(nombre);
    }
}

 

Para ambas sintaxis es posible usar operadores estándar para confeccionar consultas de agrupación (GroupBy), de combinación (Join o GroupJoin), de ordenamiento (OrderBy combinado con ThenBy o ThenByDescending por ejemplo), etc. Algunas operaciones de consulta como Count o Max, no tienen ninguna cláusula de expresión equivalente y, por tanto, deben expresarse como una llamada a método. La sintaxis de método se puede combinar con la sintaxis de consulta de varias maneras.

Como programador, tenemos la posibilidad de escribir la consulta mediante sintaxis de consulta como también con sintaxis de método. Sin embargo, en la mayoría de los casos, la sintaxis de consulta es más fácil y concisa porque utiliza muchas construcciones de lenguaje de C# familiares. Si bien, no existe ninguna diferencia semántica o de rendimiento entre las dos formas, las expresiones de consulta suelen ser más legibles que las expresiones equivalentes escritas con sintaxis de método. Un claro ejemplo que nos llevo a cambiar por sintaxis de consulta en el proyecto del que formo parte, es que la sintaxis de método resulta casi ilegible al tener una consulta con una gran cantidad de Joins o GroupJoins en secuencia donde los datos son seleccionados mediante clases anónimas. Veamos este caso:

Ejemplo con sintaxis de consulta basada en método:

 

//Join entre la tabla PermisosSet con los EmpleadosSet 
//para obtener los ids de Empresa y Articulo.    
var permisos = data.PermisosSet
    .Join(data.EmpleadosSet,
    p => p.IdLegajo,
    e => e.IdLegajo,
    (p, e) => new
    {
        p.IdEmpresa,
        p.IdArticulo
    });
 
//Join entre el IQueryable de "permisos" con los 
//EmpresasSet para obtener información de la Empresa.
var resultadoConEmpresas = data.EmpresasSet
    .Join(permisos,
    em => em.IdEmpresa,
    p => p.IdEmpresa,
    (e, p) => new
    {
        p.IdArticulo,
 
        DatosEmpresas = new
        {
            em.CodEmpresa,
            em.Descripcion
        }
    });
 
//Join entre el IQueryable de " resultadoConEmpresas " con 
//los ArticulosSet para obtener información del Articulo.
var resultadoFinal = data.ArticulosSet
    .Join(resultadoConEmpresas,
    a => a.IdArticulo,
    r => r.IdArticulo,
    (a, r) => new
    {
        DatosArticulos = new
        {
            a.CodArticulo,      
                a.Descripcion,
                a.Vigencia
        }
    });

 

Ejemplo con sintaxis de expresiones de consulta:

 

var permisos = from r in data.PermisosSet
    //Realizar todos los Joins
    join e in data.EmpleadosSet on r.IdLegajo equals e.IdLegajo
    join em in data.EmpresasSet on r.IdEmpresa equals em.IdEmpresa
    join a in data.ArticulosSet on r.IdArticulo equals a.IdArticulo
    
    //El Select se realiza al final para obtner todos los datos que se retornaran.
    select new
    {
        DatosEmpresas = new
        {
            em.CodEmpresa,
            em.Descripcion
        },
 
        DatosArticulos = new
        {
            a.CodArticulo,      
            a.Descripcion,
            a.Vigencia
        }
    };

 

Si bien las consultas devuelven los mismos resultados puede verse claramente que la consulta confeccionada mediante sintaxis de expresiones es más legible y similar a T-SQL que la realizada son sintaxis de métodos.

 

Tags: ,

ADO.NET | Entity Framework

Por donde empezar con Entity Framework

por Daniel Laco  10. enero 2010

En el blog del CIIN (Blog del Centro de Innovación en Integración de Cantabria) un excelente blog relacionado con Sharepoint publicaron una excelente recopilación de recursos de información sobre Entity Framework.

La dirección es http://geeks.ms/blogs/ciin/archive/2010/01/08/ado-net-entity-framework-recursos-para-empezar-a-meterse-en-harina.aspx

 También pueden encontrar una muy buena guía (en Inglés) en http://weblogs.asp.net/zeeshanhirani/archive/2008/12/18/my-christmas-present-to-the-entity-framework-community.aspx.  Contiene mkuy buena información, una amplia cantidad de ejemplos de mapping, Queries, etc,

También aqui dejo el link a esta herramienta excelente que es el LinqPad. En este link http://www.linqpad.net/EntityFramework.aspx  está la forma de como consultar modelos de Entity Framework.

Tags: ,

ADO.NET | Entity Framework

Acerca de los Autores

Este es el blog del equipo de VEMN SA 
Presentaremos temas que nos parezcan de interés sobre tecnología .NET, Procesos y Metodologías y todo aquello relacionado con el proceso de desarrollo de Software

Month List

BlogRoll

Download OPML file OPML