Como obtener el Connection String clásico con Entity Framework

por Andres Stang  28. enero 2011

Como sabrán Entity Framework utiliza un conection string para saber con qué base de datos trabajar, el tema es que además de contener la cadena de conexión que conocemos de toda la vida, tiene un poco más de información que utiliza para indicarle otras cosas que no vienen al caso.

Si quisiéramos recuperar la clásica cadena de conexión para, por ejemplo, no utilizar Entity Framework y acceder directamente a la base de datos con ADO.NET uno pensaria en hacer:

 

   1:  MiModeloEntities miEntities = new MiModeloEntities();
   2:  string connStringEF = miEntities.Connection.ConnectionString;

 

Pero no nos serviría! Ya que tenemos la cadena de conexión de Entity Framework que incluye metadata que antes mencionamos. Ya sé, seguramente ya estás pensando en usar expresiones regulares… Momento! La solución? Simplemente:

 

   1:  MiModeloEntities miEntities = new MiModeloEntities();
   2:  string connString = ((System.Data.EntityClient.EntityConnection)miEntities.Connection).StoreConnection.ConnectionString;

 

Y de esta manera nos evitamos tener duplicada la información en nuestra configuración y evitamos parsear el string innecesariamente.

Tags: ,

.NET | Entity Framework | ORM | SQL Server

Reportes Agiles en Team Foundation Server – Stories Overview Report

por Viviana Chelini  10. noviembre 2010

Siguiendo con los comentarios sobre los reportes ágiles de TFS 2010 iniciados en :

Bug Status Report

Bug Trend Report

Reactivation Report

Build Quality Indicators Report

Burndown and Burn Rate Report

Remaining Work Report

Status on All Iterations Report

 

Hoy comentaremos sobre:

Stories Overview Report (Agile)

El siguiente reporte muestra gráficamente información general sobre los casos de uso definido para una iteración o área determinada.

Información que proporciona el reporte

El reporte presenta una visión del trabajo realizado para el conjunto de casos de uso filtrados hasta la fecha actual.

Este reporte muestra la siguiente información sobre cada caso de uso:

Progreso del trabajo

  • % de horas completadas: un valor numérico y representación visual que muestra el porcentaje de trabajo completado.
  • Horas restantes: un valor numérico de todas las horas restantes para todas las tareas vinculadas al caso de uso o sus casos secundarios.

Estado de la prueba

  • Pruebas: un valor numérico que representa el número de casos de prueba vinculados al caso de uso o sus casos secundarios.
  • Resultados de pruebas: un valor numérico y representación visual que muestra el porcentaje de casos de prueba, agrupados según el estado de su ejecución de pruebas más reciente, donde las opciones son Superadas (verde), Con error (rojo) o Sin ejecutar (negro).
  • Errores: un valor numérico y representación visual que muestra el número de errores vinculados al caso de prueba o caso de uso, donde las opciones son Activa (azul) y Resuelto (oro).

El reporte de Información general enumera y resalta los casos según los siguientes criterios:

  • Los casos aparecen por orden de importancia, que está basado en su clasificación asignada.
  • Los casos aparecen en tipo en negrita cuando están en el estado activo o resuelto.
  • Los casos aparecen en tipo normal cuando están en el estado cerrado.
  • Los casos aparecen en tipo gris cuando su iteración o área asignada está fuera del conjunto filtrado, pero tienen tareas o casos secundarios que están dentro del conjunto filtrado de iteraciones o áreas de producto.

 

Para que el reporte sea fiable se deben de alimentar correctamente los siguientes parámetros de los elementos de trabajo:

  • Definir los casos de uso y tareas, crear un vínculo Secundario desde cada tarea a un caso de uso y crear un vínculo Secundario desde cualquier subtarea a su tarea primaria.
  • Definir y actualizar los campos Completado y Restante para cada tarea o subtarea durante la iteración o versión.
  • Definir los casos de prueba y crear el vínculo Prueba realiza por desde cada caso de prueba a un caso de uso.
  • Para cada error, crear el vínculo Prueba realiza por al caso de prueba que identificó el defecto de código o un vínculo Relacionado al caso de uso con el que est�� relacionado el error.
  • Establecer el Estado de cada error en Resuelto cuando se corrija.
  • Especificar las rutas de acceso Área e Iteración para cada caso, tarea, caso de prueba y error.

 

Análisis del reporte

El reporte de Información general muestra el progreso de trabajo global en tres áreas que son importantes para completar y cerrar un caso de uso:

  • Tareas implementadas para completar el caso de uso.
  • Casos de prueba ejecutados para asegurar la calidad de los casos implementados.
  • Errores identificados que indican los problemas con la calidad de los casos de uso.
Progreso del trabajo
  • ¿Corresponde a sus expectativas la cantidad de trabajo que resta para cada caso de uso?
  • ¿Se implementan primero los casos de uso clasificados según su relevancia?
  • ¿Cuántas pruebas se definen para cada caso de uso?¿Cuántas pruebas se superan?
  • ¿Qué casos de uso se implementan que no tienen ningún caso de prueba definido para ellos?
Progreso de la calidad
  • ¿Cuántos casos de prueba se han ejecutado para cada caso de uso y cuántos han superado las pruebas?
  • ¿Cuántos errores activos tiene cada caso de uso?
  • ¿Se encuentran errores para los casos de uso que se prueban?
  • ¿Se resuelven los errores o siguen activos?
Evaluación de riesgo
  • ¿Qué casos de uso están en riesgo?
  • ¿Qué casos de uso no son suficientemente estables para la versión?
  • ¿Qué casos de uso puede distribuir hoy el equipo?

 

Versión positiva del reporte

Un reporte positivo muestra más progreso en los casos de uso que aparecen cerca de la parte superior del reporte. En la imagen que se muestra a continuación se visualiza que el equipo ha realizado más trabajo para los casos que aparecen en el reporte.

 

 

Versión negativa del reporte

Un reporte negativo muestra una o más de los siguientes indicadores:

  • El equipo está realizando más progreso en los casos de uso que tienen un rango inferior que en los que tienen un rango superior.
  • Hay más pruebas con errores que superadas.
  • Se producen errores en las pruebas para un caso de uso, pero no se crea ningún elemento de trabajo de error.

 

Hasta la próxima.

 

Tags: , ,

ASP.NET | Javascript | ORM | TFS

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

Dos temas mas importantes de NHibernate

por Daniel Laco  14. enero 2008


Cuando uno comienza a trabajar con herramientas nuevas, siempre trata de leer manuales, documentos, etc, buscando cual es la mejor forma de comenzar a trabajar con ella.

 

En el caso de NHibernate he estado leyendo la documentación, blogs (recomiendo entre otros el de Dario Quintana), etc. en ningún lugar encontré una explicación clara sobre como utilizar dos de los pilares mas importantes de NHibernate como son el SessionFactory y el Session.

Si bien en NHibernate es importante saber como hacer los archivos de mapeo entre clases y entidades, como escribir las clases, etc, etc. mas importante aún es saber en que casos y como utilizar las dos clases mencionadas anteriormente

Asi que no voy a entrar en detalle en este articulo sobre temas particulares de cada objeto, solo les voy a dejar un par de líneas que a mi me parecieron por demás importante.

 

SessionFactory por Aplicación

Este objeto es muy costoso para NHibernate, es el levanta el archivo de mapping, configuraciones, etc. Por eso se debe usar solo una vez en la aplicación. Salvo que se necesiten trabajar con mas de un archivo de mapping al mismo tiempo, en ese caso se crean tantos SessionFactory como se necesiten.

Session por unidad de trabajo (Unit of Work)

Este es el objeto que realiza toda la conexión con la base de datos. Este objeto se debe usar cada vez que tengo que acceder a la base de datos.

La mejor forma es encerrando este objeto en un Using directamente. O sea cada vez que tenemos que acceder a los datos abrimos y cerramos la Session.

Tags:

ORM

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