Taking something that can't be done, and then doing it.

by Jiří {x2} Činčura

Custom conventions in Entity Framework 6 helping Firebird - part 2

Published 11 Mar 2013 in Entity Framework and Firebird

Follow-up post.

Few days ago I wrote a post “Custom conventions in Entity Framework 6 helping Firebird”. Arthur Vickers from Entity Framework team had a good question whether it works also for columns and tables that are generated by Entity Framework (like join tables for M:N, FK columns (if not in model), etc.). And it actually does not. :) For this you have to dig a little bit deeper and use model-based convention. For this type of convention you have to write a class as there’s (currently, alpha 3) no way to do it using fluent API in a lightweight way (and I would not expect this to change, this isn’t common scenario).

Anyway for properties to work you have to implement IDbConvention<EdmProperty> and for table IDbConvention<EntityType> (not EntitySet, you need to be able to see whether somebody set the table name already or not which for me is easier from EntityType type). Don’t ask me how I found this. A lot of trial and error. And actually a lot of memories from around 2010 and Entity Framework v1 (link, link (anybody here ever explored MetadataProperties?)) :).

class FirebirdFriendlyModelConvention : IDbConvention<EdmProperty>, IDbConvention<EntityType>
    public void Apply(EdmProperty dbDataModelItem, EdmModel model)
        var preferredName = (string)dbDataModelItem.Annotations.First(x => x.Name == "PreferredName").Value;
        if (preferredName == dbDataModelItem.Name)
            dbDataModelItem.Name = FirebirdNamingConvention.CreateName(dbDataModelItem.Name);

    EntityType GetRootType(EntityType entityType)
        if (entityType.BaseType != null)
            return GetRootType((EntityType)entityType.BaseType);
        return entityType;

    string GetTableName(ICollection<DataModelAnnotation> anotations)
        var anotation = anotations.FirstOrDefault(x => x.Name == "TableName");
        if (anotation == null)
            return null;
        return (string)anotation.Value;

    public void Apply(EntityType dbDataModelItem, EdmModel model)
        var entitySet = model.Containers.First().EntitySets.SingleOrDefault(e => e.ElementType == GetRootType(dbDataModelItem));
        var tableName = GetTableName(dbDataModelItem.Annotations);
        if (tableName == null)
            tableName = FirebirdNamingConvention.CreateName(dbDataModelItem.Name);
            entitySet.GetType().GetProperty("Table").SetValue(entitySet, tableName);

As you can see it’s not magic, if you know where to look at. Because the Table property is currently (alpha 3) not public I was forced to use reflection. There’s the related work item.

With this conventions, hopefully, all the tables and columns, except specified explicitly, will be renamed to “common” Firebird naming.