Entity FrameWork – Metadata

Como sabéis la metadata se define como la información que se conoce sobre los propios datos, cuando hablamos de entity framework, esta contendrá información sobre las entidades, campos y relaciones. En este ejemplo estaba buscando la posibilidad de conocer el maxLength de un campo de una entidad determinada, de esta forma podria configurar algunos de mis controles en tiempo de ejecución.

Cuando configuramos un grid necesitamos configurar el maxLength de cada campo para impedir un desbordamiento en la actualización, para evitar establecer el valor de forma manual en cada columna, pues si en algún momento cambio este valor, estaría obligado a variar esta información en todos los controles de mi aplicación donde utilice este campo. La metadata puede proporcionar esta información para configurar los controles en tiempo de ejecución evitando cambiar estos datos si en el algún momento altero la estructura de mis tablas. De la misma forma podemos configurar la precisión y la escala en valores decimales, nombre de los campos para el databinding, aceptación de valores nulos, configuración de campos de solo lectura, etc.

La automatización de estos procesos a traves de los metadatos evitara numerosos errores y nos permitirá realizar cambios de una forma más eficaz.

En otras ocasiones esta información nos permitira generar sentencias Sql en tiempo de ejecución, generalizar consultas y funciones en nuestros proyectos.

En Entity framework la metadata esta almacenada en el archivo edmx en formato xml. En este ejemplo el archivo xml contiene información diversa en cada uno de los campos, maxlenght en los casos que utilizemos cadenas, precision y escala en los valores decimales.

   1: <Property Name="Empresa" Type="nvarchar" MaxLength="50" />
   2: <Property Name="Transporte_factor" Type="decimal" Nullable="false" Precision="6" Scale="2" />        

He desarrollado este pequeño programa que nos permitirá conocer el maxLength de cualquier campo de una entidad,

/// <summary>
/// Retorna el maxlenght de un campo de una entidad y un contexto determinados
/// </summary>
/// <param name="context">Contexto del que se quieren recuperar las entidades</param>
/// <param name="entity">Nombre de la entidad</param>
/// <param name="field">Nombre del campo</param>
/// <returns>Retorna la longitud de la entidad, en caso de no encontrarlo retorna -1</returns>
public static int GetMaxlenght(ObjectContext context, EntityObject entity, string field)
{
    if (context != null && entity != null && !string.IsNullOrEmpty(field))
    {
        EntityContainer container;
        if (context.MetadataWorkspace.TryGetEntityContainer(context.DefaultContainerName, DataSpace.CSpace, out container))
        {
            EntitySet entitySet;
            if (container.TryGetEntitySetByName(entity.ToString().Split('.')[1], false, out entitySet))
            {
                const string mlenght = "MaxLength";
                if (entitySet.ElementType.Members.Contains(field) && entitySet.ElementType.Members[field].TypeUsage.Facets.Contains(mlenght))
                {
                    object smaxlenght = entitySet.ElementType.Members[field].TypeUsage.Facets[mlenght].Value;
 
                    if (smaxlenght != null)
                    {
                        int maxlenght;
                        if (int.TryParse(smaxlenght.ToString(), out maxlenght))
                        {
                            return maxlenght;
                        }
                    }
                }
            }
        }
    }
    return -1;
}

El ejemplo de uso seria algo así:

   1: using (NorthwindEFEntities context = new NorthwindEFEntities())
   2: {
   3:     Employees employees = new Employees();
   4:     EdmTools.GetMaxlenght(context, employees, "FirstName");
   5: }

Si quisieramos conocer otro factor, tan solo tendriamos que alterar el valor de la constante definida en:

const string mlenght = "MaxLength"

Aunque para el ejemplo anterior quizás lo más lógico sería realizar un método extensor para acceder a este tipo de información para poder hacer algo asi:

int maxlenght = employess.GetMetadata(employess.FirstName, Attributes.Maxlenght);

Cuando lo desarrolle pondré este ejemplo.

Como veis en el depurador las facetas pueden proporcionarnos más información, default value, nullable, etc.

image

El siguiente ejemplo está basado en el mismo proceso y devuelve información a través de un array con el contenido del maxLength de todas las columnas:

   1: /// <summary>
   2: /// Retorna una colección de campos valor con el maxlenght de cada uno de los campos de una entidad
   3: /// </summary>
   4: /// <param name="context">Contexto del que se quieren recuperar las entidades</param>
   5: /// <param name="entity">Entidad</param>
   6: /// <returns>Retorna un diccionario campo valor con la longitud de cada uno de los campos, en caso de no encontrarlo retorna -1</returns>
   7: public static Dictionary<EdmMember, int> GetMaxlenght(ObjectContext context, EntityObject entity)
   8: {
   9:     Dictionary<EdmMember, int> edmFieldsMaxlenght = new Dictionary<EdmMember, int>();
  10:     if (context != null && entity != null)
  11:     {
  12:         EntityContainer container;
  13:         if (context.MetadataWorkspace.TryGetEntityContainer(context.DefaultContainerName, DataSpace.CSpace, out container))
  14:         {
  15:             EntitySet entitySet;
  16:             if (container.TryGetEntitySetByName(entity.ToString().Split('.')[1], false, out entitySet))
  17:             {
  18:                 foreach (EdmMember member in entitySet.ElementType.Members)
  19:                 {
  20:                     const string mlenght = "MaxLength";
  21:  
  22:                     if (entitySet.ElementType.Members.Contains(member.Name) && entitySet.ElementType.Members[member.Name].TypeUsage.Facets.Contains(mlenght))
  23:                     {
  24:                         object smaxlenght = entitySet.ElementType.Members[member.Name].TypeUsage.Facets[mlenght].Value;
  25:  
  26:                         if (smaxlenght != null)
  27:                         {
  28:                             int maxlenght;
  29:                             if (int.TryParse(smaxlenght.ToString(), out maxlenght))
  30:                             {
  31:                                 edmFieldsMaxlenght.Add(member, maxlenght);
  32:                             }
  33:                         }
  34:                     }
  35:                 }
  36:             }
  37:         }
  38:     }
  39:     return edmFieldsMaxlenght;
  40: }
Buscando información encontré este blog http://www.scip.be/index.php?Page=ArticlesNET24, en el que proponen otro ejemplo muy interesante. Solo que aquí no puede acceder al maxlengh, es curioso, únicamente a los valores por defecto, si es nullable, etc.

1:
var query = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)
   2:                 .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
   3:             let m = (meta as EntityType)
   4:             let properties = m.Properties
   5:             select new
   6:             {
   7:  
   8:                 EntityName = m.Name,
   9:                 MembersCount = m.Members.Count,
  10:                 KeyMembersCount = m.KeyMembers.Count,
  11:                 PropertyNames = from p in properties
  12:                                 select new
  13:                                 {
  14:                                     p.Name,
  15:                                     p.Nullable,
  16:                                     p.DefaultValue,
  17:                 Documentation,
  18:                                     Type = p.TypeUsage.EdmType.Name
  19:                                 }
  20:             };

No he probado a leer los metadatos de una entidad heredada, aunque en este caso podriamos averiguar su base y realizar la consulta. Utilizando como base el ejemplo anterior podemos facilmente ver todas la entidades que están derivadas.

   1: public static IEnumerable GetEntityNamesBaseNames(ObjectContext context)
   2: {
   3:     var query = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)
   4:                     .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
   5:                 let m = (meta as EntityType)
   6:                 where m.BaseType != null
   7:                 select new
   8:                 {
   9:                     m.Name,
  10:                     BaseTypeName = m.BaseType != null ? m.BaseType.Name : null,
  11:                 };
  12:     return query;
  13: }

Espero que os sirva…

3 comentarios en “Entity FrameWork – Metadata”

  1. I trying to get the Maxlenght but only get null value

    Model.

    < ?xml version="1.0" encoding="utf-8"?>





















































    Form

    private void button1_Click(object sender, EventArgs e)
    {
    Area area = new Area();
    dbsgiEntities db = new dbsgiEntities();
    int? maxlen = GetMaxlenght(db, area, “dc_area”);
    textBox1.Text = maxlen.ToString();
    }

    ///

    ///
    ///

    /// /// /// ///
    private static int GetMaxlenght(ObjectContext context, EntityObject entity, string field)
    {

    if (context != null && entity != null && !string.IsNullOrEmpty(field))
    {
    EntityContainer container;
    if (context.MetadataWorkspace.TryGetEntityContainer(context.DefaultContainerName, DataSpace.CSpace, out container))
    {
    EntitySet entitySet;
    if (container.TryGetEntitySetByName(“Areas”, false, out entitySet))
    {
    const string mlenght = “MaxLength”;
    if (entitySet.ElementType.Members.Contains(field) && entitySet.ElementType.Members[field].TypeUsage.Facets.Contains(mlenght))
    {
    object smaxlenght = entitySet.ElementType.Members[field].TypeUsage.Facets[mlenght].Value;
    if (smaxlenght != null)
    {
    int maxlenght;
    if (int.TryParse(smaxlenght.ToString(), out maxlenght))
    {
    return maxlenght;
    }
    }
    }
    }
    }
    }
    return -1;
    }

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *