none
Dynamic way to Generate EntityTypeConfiguration : The type 'TResult' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method RRS feed

  • Question

  • I was thinking to generate EntityTypeConfiguration dynamically from run time and i don't want any EF dependency in Models[That is why i avoid Data Annotation].

    So I declare a custom attribute(or can be any configuration file later on)

    [AttributeUsage(AttributeTargets.Property, AllowMultiple=true )]
        public class PersistableMemberAttribute : Attribute
        {
            public bool Iskey;
            public bool IsRequired;
            public bool IsIgnored;
            public bool IsMany;
            public string HasForeignKey;
            public bool PropertyIsRequired;
            public bool PropertyIsOptional;
        }

    And here is one of my Models is look like:

        public class Blog
        {
            [PersistableMember(Iskey=true)]
            public Guid BlogId { get; set; }
    
            [PersistableMember(PropertyIsRequired = true)]
            public string Name { get; set; }
            
            public string Url { get; set; }
    
            [PersistableMember(IsIgnored=true)]        
            public int Rating { get; set; }
    
            [PersistableMember(IsMany =true)]
            public ICollection<Post> Posts { get; set; }
        }

    Now I am going to write a generic EntityTypeConfiguration , which will create the configuration dynamically on run time based on the attribute values

      public class GenericEntityConfiguration<T> : EntityTypeConfiguration<T> where T : class
        {
            public GenericEntityConfiguration()
            {
                var members = typeof(T).GetProperties();
                if (null != members)
                {
                    foreach (var property in members)
                    {
                        var attrb= property.GetCustomAttributes(typeof( PersistableMemberAttribute ),false).OfType<PersistableMemberAttribute>();
                        if (attrb != null && attrb.Count() > 0)
                        {
                            foreach (var memberAttributute in attrb)
                            {
                                if (memberAttributute.Iskey || memberAttributute.IsIgnored)
                                {
                                    var entityMethod = this.GetType().GetMethod("Setkey");
                                    entityMethod.MakeGenericMethod(property.PropertyType)
                                      .Invoke(this, new object[] { property, memberAttributute });
                                }
    
                                if (memberAttributute.IsRequired)
                                {
                                    var entityMethod = this.GetType().GetMethod("SetRequired");
                                    entityMethod.MakeGenericMethod(property.PropertyType)
                                      .Invoke(this, new object[] { property, memberAttributute });
                                }
    
                                if (memberAttributute.PropertyIsRequired || memberAttributute.PropertyIsOptional)
                                {
                                    var entityMethod = this.GetType().GetMethod("SetPropertyConfiguration");
                                    entityMethod.MakeGenericMethod(property.PropertyType)
                                      .Invoke(this, new object[] { property, memberAttributute });
                                }
                            }
                        }
                    }
                }
              
            }
    
            public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
            {
                var functorParam = Expression.Parameter(typeof(T));
                var lambda = Expression.Lambda(
                    Expression.Property(functorParam, propertyInfo)
                , functorParam);
    
                if (attribute.PropertyIsRequired)
                {
                    this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
                }
                if (attribute.PropertyIsOptional)
                {
                    this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
    
                }
            }
    
            public void Setkey<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
            {
                var functorParam = Expression.Parameter(typeof(T));
                var lambda = Expression.Lambda(
                    Expression.Property(functorParam, propertyInfo)
                , functorParam);
    
                if (attribute.Iskey)
                {
                    this.HasKey<TResult>((Expression<Func<T,TResult>>)lambda);
                }
                if (attribute.IsIgnored)
                {
                    this.Ignore<TResult>((Expression<Func<T, TResult>>)lambda);
                }
            }
    
            public void SetRequired<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) where TResult : class
            {
                var functorParam = Expression.Parameter(typeof(T));
                var lambda = Expression.Lambda(
                    Expression.Property(functorParam, propertyInfo)
                , functorParam);
                if (attribute.IsRequired)
                {
                    this.HasRequired<TResult>((Expression<Func<T, TResult>>)lambda);
                }
            }
    
        }

    But i got the compilation error of

    Error    1    The type 'TResult' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration<TStructuralType>.Property<T>(System.Linq.Expressions.Expression<System.Func<TStructuralType,T>>)'    D:\R&D\UpdateStorePOC\UpdateStorePOC\Data\GenericEntityConfiguration.cs    63    17    UpdateStorePOC

    which for :

                if (attribute.PropertyIsRequired)
                {
                    this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
                }
                if (attribute.PropertyIsOptional)
                {
                    this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
                }


    that means that I need to put a constraint on my method to restrict it to a value type. In C#, this is done with the ‘struct’ keyword.

    public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) Where TResult : struct

    But Its not the solution since my property type can be a class e.g string or int, bool double, etc . So it is not at all clear that I can send them into this method. Please help me to solve this issue whether there is any other way to do  it.



    • Edited by Pulok Monday, November 12, 2012 12:38 PM edit some spelling mistake and language
    Friday, November 9, 2012 12:06 PM

All replies