Reputation: 51
I am rewriting a legacy system to use Entity Framework. The old system had entities where half of the properties were mapped to DB columns and the other half not. To indicate that a property had to be mapped, the property was decorated with a [Field] attribute. All other properties were ignored.
This is the opposite of what EF does. By convention, EF maps all public properties with a getter and setter to a DB field unless the property is decorated with [NotMapped] data annotation or Ignore is called on for that property using the fluent API on model creating.
I want to override the EF convention to work as the old system. ie Ignore properties that do not have the FieldAttribute. I know that this could be done by adding [NotMapped] to all the properties, but I'm looking for a way to do this dynamically so that i don't have to change every single entity (there are hundreds)
There's not system convention to remove or override for this that i can see
https://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions.aspx
I've tried the following code to call ignore using reflection with no luck :
modelBuilder.Properties().Configure((configuration) =>
{
var attributes = configuration.ClrPropertyInfo.GetCustomAttributes(inherit: false);
var fieldAttribute = attributes.FirstOrDefault(x => x.GetType() == typeof(FieldAttribute) || x.GetType() == typeof(KeyAttribute));
if (fieldAttribute == null)
{
var entityMethod = modelBuilder.GetType().GetMethod("Entity");
var entityConfiguration = entityMethod.MakeGenericMethod(configuration.ClrPropertyInfo.ReflectedType).Invoke(modelBuilder, new object[] { });
MethodInfo ignoreMethod = entityConfiguration.GetType()
.GetMethod("Ignore")
.MakeGenericMethod(configuration.ClrPropertyInfo.PropertyType);
var parameter = Expression.Parameter(configuration.ClrPropertyInfo.ReflectedType);
var memberExpression = Expression.Property(parameter, configuration.ClrPropertyInfo.Name);
var lambdaExpression = Expression.Lambda(memberExpression, parameter);
ignoreMethod.Invoke(entityConfiguration, new[] { lambdaExpression });
}
});
This looks like it works, as the property is added to the ignore list of the entity configuration. But EF still tries to map the property to a non existent DB field and throws an Invalid column exception.
Does anyone have any other ideas?
Upvotes: 3
Views: 1290
Reputation: 51
I found a solution to the problem. If i come at this from the TypeConventionConfiguration instead of the PropertyConventionConfiguration it works. I probably had some bug in my code above. This way i need to use less reflection...
modelBuilder.Types().Configure((entityConfiguration) =>
{
const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
foreach (var propertyInfo in entityConfiguration.ClrType.GetProperties(bindingFlags))
{
var attributes = propertyInfo.GetCustomAttributes(inherit: false);
var fieldAttribute = attributes.FirstOrDefault(x => x.GetType() == typeof(FieldAttribute) || x.GetType() == typeof(KeyAttribute));
if (fieldAttribute == null)
{
entityConfiguration.Ignore(propertyInfo);
}
}
});
Upvotes: 2