2

Has anyone found a solution or workaround to the issue of how Entity Framework v4 supports column names prefixed with an underscore? I've noticed that properties on entities created by EFv4 have the underscore prefix replaced with a "C_" prefix. So, for example, the database column:

Order._activity

becomes the entity property:

Order.C_activity

Then when I attempt a query I understandably get the error:

The data reader is incompatible with the specified 'CorporateModel.Order'. A member of the type, 'C_activity', does not have a corresponding column in the data reader with the same name.

This is a legacy database with dependent application so changing the column names in the database is not an option.

Thanks for any input.

Kris Ivanov
  • 10,476
  • 1
  • 24
  • 35
BitMask777
  • 2,543
  • 26
  • 36

2 Answers2

1

OK, I don't have exact solution for you, but have a similar situation. EF Generated fields ends with ID if when referencing another table. Example. Table Person has a column JobID instead of Job. We don't like that. This was the issue: http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/f8ddb2be-78c9-4296-b293-37b7bc8e8fd7

So what my team mate did is to "override" the default convention. Please forgive if this is not exactly your case. I think it should give you some hints. This is with EF V 4.1

 public class ASRCDb : DbContext, IUnitOfWork
{
    public void Complete()
    {
        SaveChanges();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
        AddAllEntities(modelBuilder);
    }

    static void AddAllEntities(DbModelBuilder modelBuilder)
    {
        var entity = typeof(DbModelBuilder).GetMethod("Entity");
        foreach (var entityType in GetEntityTypes())
        {
            var entityTypeConfiguration = entity.MakeGenericMethod(entityType).Invoke(modelBuilder, null);
            foreach (var propertyInfo in GetReferenceProperties(entityType))
                ConfigureRelationship(propertyInfo, entityTypeConfiguration);
        }
    }

    static IEnumerable<PropertyInfo> GetReferenceProperties(Type entityType)
    {
        return entityType.GetProperties().Where(p => typeof(IEntity).IsAssignableFrom(p.PropertyType));
    }

    static IEnumerable<Type> GetEntityTypes()
    {
        return typeof(Entity).Assembly.GetTypes().Where(type => type.IsClass && !type.IsAbstract);
    }

    static void ConfigureRelationship(PropertyInfo propertyInfo, dynamic entityTypeConfiguration)
    {
        var required = propertyInfo.GetCustomAttributes(typeof(RequiredAttribute), true).Any();
        var navigation = required
                             ? entityTypeConfiguration.HasRequired(GetPropertyExpression(propertyInfo))
                             : entityTypeConfiguration.HasOptional(GetPropertyExpression(propertyInfo));
        UsePropertyNameAsColumnName(propertyInfo, navigation);
    }

    static void UsePropertyNameAsColumnName(PropertyInfo propertyInfo, dynamic navigation)
    {
        Action<ForeignKeyAssociationMappingConfiguration> mapKey = x => x.MapKey(propertyInfo.Name);
        navigation.WithMany().Map(mapKey);
    }

    static dynamic GetPropertyExpression(PropertyInfo propertyInfo)
    {
        var parameter = Expression.Parameter(propertyInfo.ReflectedType);
        return Expression.Lambda(
            typeof(Func<,>).MakeGenericType(propertyInfo.ReflectedType, propertyInfo.PropertyType),
            Expression.Property(parameter, propertyInfo),
            parameter);
    }
}

All the Credit is to my buddy Diego Mijelshon.

Marcote
  • 2,977
  • 1
  • 25
  • 24
  • Thanks for the response. I thought about some type of override but wasn't sure if overriding this particular issue (the underscore "conversion") is just overriding a convention or might actually cause things to break. I'll take a look into the approach shown in your code to see if it might work for my case. – BitMask777 Mar 30 '11 at 16:20
  • I might be misunderstanding, but it seems this approach will work when generating the database. I'm going the other way round: generating the model from an existing database, so I'm not sure it's applicable. I'm now looking into adding an ADO.NET EntityObject Generator to my project and modifying the .tt file for code generation. Additional comments/answers are welcome. – BitMask777 Mar 30 '11 at 20:45
  • Ah, it was my mistake I misunderstood the whole thing. I don't have experience generating code using the templates but I've read that is extensible. Good luck – Marcote Mar 30 '11 at 20:50
  • I'm beginning to think this is not possible. If I try to change the property name directly in the model browser so that it begins with an underscore then it is rejected with an "invalid name" error. So, I suspect that even if I do manage to change it with a T4 template then I will have problems. – BitMask777 Mar 31 '11 at 15:38
  • I would post this in the EF Forum. It's moderated by the EF Devs. They will tell you first hand if this is possible or not. If not, NH will be your path I believe. Good luck. – Marcote Mar 31 '11 at 15:46
  • 1
    I went with another solution: using LINQ to SQL to build the model instead of EF, then used the reflection provider to implement IQueryable/IUpdatable on the model (see [here](http://msdn.microsoft.com/en-us/library/ee373841.aspx#Y228)) so I could expose it via a WCF Data Service. Keeps my underscores intact and seems to work fine. @Markust I will take your suggestion to get some closure on my original question. +1 for the interaction. Thanks. – BitMask777 Mar 31 '11 at 18:28
1

It seems that EF does not support property names that start with an underscore and that this is a pattern constraint enforced by the EDM schemas. One example is the SSDL schema.

I went with another solution: using LINQ to SQL instead of EF to build the model, then using the reflection provider to implement IQueryable/IUpdatable on the model (see here) so I could expose it via a WCF Data Service. This keeps underscores intact in the model and in the resulting OData returned from the service.

However, there is a caveat: since Microsoft client proxy code generators use the EdmItemCollection to parse the metadata during generation, attempting to generate a proxy (e.g. in Visual Studio) fails for a service with entity properties starting with underscores. You will need to consuming the OData from such a service without the aid of one of these proxy generators.

BitMask777
  • 2,543
  • 26
  • 36