08 March, 2015

How to get database column property for entity?

Why getting the column property for the entity is a problem?

When we use Entity Framework, we often want to get some information about some columns, that are a part of the database table, which is behind the entity. The most elegant way of getting this information is to use a partial class which contains the decorated (with attributes) properties. It may look like below:

[Column("Description")]
[Required(ErrorMessage = "Description is mandatory!")]
[StringLength(255, MinimumLength = 5, ErrorMessage = "The description must contain more than 5 and less then 255 characters!")]
public string Description{ get; set; }

This solution is the most elegant and easiest to use. You can use e.g. the messages in the higher layers of your application and use the lenght in validation of the objects also on the higher layers of the application. Unfortunatly, it is hard to use this mechanism in the application that has a big database and you have very limited time to make a change.

Quick solution

If you have the problem as stated above, you can use a little bit different solution - get access to the properties by the Reflection. The main idea is to access the properties of the entity by its names and types represented as strings like below:

        public static object GetInfoAboutColumn<TypeOfEntity>(ObjectContext objectContext, 
                              Expression<Func<TypeOfEntity, string>> column, 
                              string typeName, 
                              string propertyName)
        {
            object resultValue = null;
            Type entType = typeof(TypeOfEntity); //we need to know the type of the entity, so we know what we should look for
            string columnName = ((MemberExpression)column.Body).Member.Name; //Get the name of the column (field) in entity
            if (objectContext != null)
            {
               // Get collection of items from the context.
               ReadOnlyCollection<GlobalItem> globalItems = objectContext.MetadataWorkspace.GetItems(DataSpace.CSpace);
               if (globalItems != null)
               {
                 // Get properties of the given type and name from the given entity.
                 var allPropertiesOfType = 
                                 GetAllPropertiesOfType<TypeOfEntity>(typeName, globalItems, columnName, entType);
                 IEnumerable<object> propertyResults = 
                                 allPropertiesOfType.Select(sel => sel.TypeUsage.Facets[propertyName].Value).ToList();
                 if (propertyResults.Any())
                 {
                     resultValue = propertyResults.First(); // Get the value which we were looking for.
                 }
               }
            }
            return resultValue;
        }

The most interesting of this solution is the mechanism of looking for the value, that we are interested in the collection of the entities. It can be done by the LINQ query as below:


        private static IEnumerable<EdmProperty> GetAllPropertiesOfType<TypeOfEntity>(string typeName, 
                                                     ReadOnlyCollection<GlobalItem> globalItems, 
                                                     string columnName, 
                                                     Type entType)
        {
            IEnumerable<EdmProperty> allPropertiesOfType = globalItems
                .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                .SelectMany(meta => ((EntityType) meta)
                    .Properties
                    .Where(p => p.Name == columnName
                                && p.TypeUsage.EdmType.Name == typeName
                                && p.DeclaringType.Name == entType.Name));
            return allPropertiesOfType;
        }

You can test it for example by trying to get "MaxLength" property of any entity. Cheers!

0 comments:

Post a Comment