Using Singular Table Names with EF Core 2

Viewed 9224

I want my domain class name to match my db table name (no pluralisation).

In EF Core 1.1, I used this code to do that:

public static void RemovePluralisingTableNameConvention(this ModelBuilder modelBuilder)
{
    foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
    {
        entityType.Relational().TableName = entityType.DisplayName();
    }
}

In EF Core 2.0, this code doesn't compile as Relational() is not a method on IMutableEntityType. Anyway, in EF Core 2.0, they have added IPluralizer, documented here:

https://github.com/aspnet/EntityFramework.Docs/blob/master/entity-framework/core/what-is-new/index.md#pluralization-hook-for-dbcontext-scaffolding

There aren't many examples to show how to achieve the same behaviour that I had before. Any clue of how to remove pluralisation in EF Core 2?

5 Answers

You can do it this way without using internal EF API calls by using the ClrType.Name

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        // Use the entity name instead of the Context.DbSet<T> name
        // refs https://docs.microsoft.com/en-us/ef/core/modeling/entity-types?tabs=fluent-api#table-name
        modelBuilder.Entity(entityType.ClrType).ToTable(entityType.ClrType.Name);
    }
}

You can use exactly the same code. Relational() is extension method defined in the RelationalMetadataExtensions class inside Microsoft.EntityFrameworkCore.Relational.dll assembly, so make sure you are referencing it.

What about IPluralizer, as you can see from the link it's just a Pluralization hook for DbContext Scaffolding, i.e. entity class generation from database, used to singularize entity type names and pluralize DbSet names. It's not used for table name generation. The default table name convention is explained in Table Mapping section of the documentation:

By convention, each entity will be setup to map to a table with the same name as the DbSet<TEntity> property that exposes the entity on the derived context. If no DbSet<TEntity> is included for the given entity, the class name is used.

In case anyone wants to try in .NET Core 3.1, you can build extension method as

public static class ModelBuilderExtension
{
    /// <summary>
    /// Remove pluralizing table name convention to create table name in singular form.
    /// </summary>       
    public static void RemovePluralizingTableNameConvention(this ModelBuilder modelBuilder)
    {
        foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes())
        {
            entityType.SetTableName(entityType.DisplayName());
        }
    }
}

Ensure you install the dependent package: Microsoft.EntityFrameworkCore.Relational

This is the extension of @Vicram answer. I applied it in EF Core 5

modelBuilder.Model.GetEntityTypes()            
    .Configure(e => e.SetTableName(e.DisplayName()));

but then if you have value objects in your domain they will all be treated as entity types and created as tables in the database. If your value objects all inherit from a base type like ValueObject you can use the following:

modelBuilder.Model.GetEntityTypes()            
    .Where(x => !x.ClrType.IsSubclassOf(typeof(ValueObject)))
    .Configure(e => e.SetTableName(e.DisplayName()));

I have not checked other EF core versions but surely it is the case in version 5.

Another drawback in EF Core 5 is that when you use inheritance in your entity model, setting tables names changes from Table-per-Hierarchy (TPH) to Table-per-Type (TPT)

You could use the following alternative (assuming your entities derive from BaseEntity class)

modelBuilder.Model.GetEntityTypes()
    .Where(x => x.ClrType.BaseType == typeof(BaseEntity))
    .Configure(e => e.SetTableName(e.DisplayName()));

Where Configure extension is

public static class ModelBuilderExtensions
{
    public static void Configure(this IEnumerable<IMutableEntityType> entityTypes, Action<IMutableEntityType> convention)
    {
        foreach (var entityType in entityTypes)
        {
            convention(entityType);
        }
    }

    public static void Configure(this IEnumerable<IMutableProperty> propertyTypes, Action<IMutableProperty> convention)
    {
        foreach (var propertyType in propertyTypes)
        {
            convention(propertyType);
        }
    }
}
Related