Change name of Identity Column for all Entities


Question

I am in the process of creating a domain model and would like to have a "BaseEntity" class with an "Id" property (and some other audit tracking stuff). The Id property is the primary key and each Entity in my Domain Model will inherit from the BaseEntity class. Pretty straightforward stuff.....

public class BaseEntity
{
    [Key]
    public int Id { get; set; }

    public DateTime LastUpdate { get; set; }
    public string LastUpdateBy { get; set; }
}
public class Location : BaseEntity
{
    [Required]
    public string Name { get; set; }

    public string Description { get; set; }
}

Using the example above, I would like to map the "Id" field to a "LocationId" column. I understand that I can use the modelBuilder to do this for each entity explicitly by doing something like this:

modelBuilder.Entity<Location>().Property(s => s.Id).HasColumnName("LocationId");

But I would like to do this for every Entity in my domain model and it would be ugly.

I tried the following bit of reflection but did not have any luck. For whatever reason, the compiler "cannot resolve symbol type":

foreach (var type in GetTypesInNamespace(Assembly.Load("Domain.Model"),"Domain.Model"))
{
    modelBuilder.Entity<type>().Property(x=>x.Id).....
}

Is there a way to define a convention to override the default PrimaryKey convention to map my "Id" property to a "ClassNameId" property in the database? I am using Entity Framework 6.

Accepted Answer

You should take a look at Custom Code First Conventions. You need EF6 for it to work, but it looks like you're already using it.
Just to give you an overview, take a look at the following convention I've used to convert PascalCase names to underscore names. It includes a convention for id properties... It also includes an optional table name prefix.

public class UnderscoreNamingConvention : IConfigurationConvention<PropertyInfo, PrimitivePropertyConfiguration>,
                                          IConfigurationConvention<Type, ModelConfiguration>
{
    public UnderscoreNamingConvention()
    {
        IdFieldName = "Id";
    }

    public string TableNamePrefix { get; set; }

    public string IdFieldName { get; set; }

    public void Apply(PropertyInfo propertyInfo, Func<PrimitivePropertyConfiguration> configuration)
    {
        var columnName = propertyInfo.Name;

        if (propertyInfo.Name == IdFieldName)
            columnName = propertyInfo.ReflectedType.Name + IdFieldName;

        configuration().ColumnName = ToUnderscore(columnName);
    }

    public void Apply(Type type, Func<ModelConfiguration> configuration)
    {
        var entityTypeConfiguration = configuration().Entity(type);
        if (entityTypeConfiguration.IsTableNameConfigured) return;

        var tableName = ToUnderscore(type.Name);

        if (!string.IsNullOrEmpty(TableNamePrefix))
        {
            tableName = string.Format("{0}_{1}", TableNamePrefix, tableName);
        }

        entityTypeConfiguration.ToTable(tableName);
    }

    public static string ToUnderscore(string value)
    {
        return Regex.Replace(value, "(\\B[A-Z])", "_$1").ToLowerInvariant();
    }
}

You use it like this

modelBuilder.Conventions.Add(new UnderscoreNamingConvention { TableNamePrefix = "app" });

EDIT: In your case, the Apply method should be something like this:

public void Apply(PropertyInfo propertyInfo, Func<PrimitivePropertyConfiguration> configuration)
{
    if (propertyInfo.Name == "Id")
    {
        configuration().ColumnName = propertyInfo.ReflectedType.Name + "Id";
    }
}

Popular Answer

Try this out in your DbContext class;

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<int>()
      .Where(p => p.Name.Equals("Id"))
      .Configure(c => c.HasColumnName(c.ClrPropertyInfo.ReflectedType.Name + "Id"));
}

int is the CLR Type of my Primary Key fields. I want to refer to all keys in code as Id but DBA's require keys to be Id with Table entity name prefix. Above gives me exactly what I want in my created database.

Entity Framework 6.x is required.





Licensed under: CC-BY-SA
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why