samedi 30 mai 2015

How to configure property in Entity Framework with Type and PropertyInfo

If I had a simple class like this

class Person
{
    public int Id { get; set; }
    // ...
}

and I wanted "do something" in EF OnModelCreating to the Id property, such as:

modelBuilder.Entity<Person>().Property( _p => _p.Id ).HasDatabaseGeneratedOption( DatabaseGeneratedOption.None );

I have no problem. However, when I have the Type and Property:

var entityType = typeof(Person);
var propInfo = entityType.GetProperty("Id");

I want a function such as

ModelEntityProperty( modelBuilder, propertyType, entityType).HasDatabaseGeneratedOption( DatabaseGeneratedOption.None );

My question: Does EntityFramework allow one to configure entities/properties using reflection information? Or is it exclusively using these LambdaExpressions?

I ended up writing this function, but it is long and in my opinion much uglier than what may be available:

private PrimitivePropertyConfiguration ModelEntityProperty( 
    DbModelBuilder p_model, 
    PropertyInfo p_propInfo, 
    Type p_entityType = null )
{
    // If the entityType was not set, then use the property's declaring type
    var entityType = (p_entityType == null) ? p_propInfo.DeclaringType : p_entityType;

    // Get the Entity <> method- a generic method
    var genericEntityMethod = typeof( DbModelBuilder ).GetMethod( "Entity", new Type[0] );

    // Get the actual method for the Type we're interested in
    var entityMethod = genericEntityMethod.MakeGenericMethod( new Type[] { entityType } );

    // get the return value of .Entity{p_type}()
    var theEntityConfigurator = entityMethod.Invoke( p_model, new object[0] );


    // I really don't like this, but it works (for now, until they change something)
    var propMethod = theEntityConfigurator
        .GetType()
        .GetMethods( BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public )
        .Where( _mi => _mi.Name == "Property" && _mi.IsGenericMethod )
        .First()
        .MakeGenericMethod( p_propInfo.PropertyType );
    // That whole ugly mess should have been a GetMethod call, but I don't know how
    // to set the parameter type to make sure the correct version of the method is
    // returned unambiguously

    // Build the expression that will be used to identify the property
    var paramExpr = Expression.Parameter( entityType );
    var memberExpr = Expression.MakeMemberAccess( paramExpr, p_propInfo );
    var lambdaExpr = Expression.Lambda( memberExpr, paramExpr );

    // Invoke the correct version of the Property method with the correct parameter
    var thePropertyConfiguration = propMethod.Invoke( 
        theEntityConfigurator, 
        new object[] { lambdaExpr } );

    // and return that thing
    return thePropertyConfiguration as PrimitivePropertyConfiguration;
}

This function works perfectly for this example, but it needs help to be more general (e.g. DateTimes, etc. don't work). Is there a better or more elegant way of doing this "natively" within EF? Or is this an appropriate method, assuming its fixed for the various ValueTypes that the "Property" method can handle?





Aucun commentaire:

Enregistrer un commentaire