66

Is there a way to do what this code did in EF Core RC 2?

protected override void OnModelCreating(ModelBuilder modelBuilder)
{    
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
Askolein
  • 3,250
  • 3
  • 28
  • 40
Paul Speranza
  • 2,302
  • 8
  • 26
  • 43

8 Answers8

133

There is no convention for this as of EF RC2 build. This is from EF Core team:

In past pre-release of EF Core, the table name for an entity was the same as the entity class name. In RC2 we now use the name of the DbSet property. If no DbSet property is defined for the given entity type, then the entity class name is used.


Now if you want to revert back to the RC1 naming conventions for tables, you have 3 ways to go with:


1. Choosing Singular Names for DbSet Properties:

One way is to singularize your DbSet property names (which I don't like). Say for example you have a Book entity and you want to map to a Book table:

public DbSet<Book> Book { get; set; }


2. Using ToTable() Fluent API:

You can of course always use fluent API to override any convention in place and dictate the table name to whatever you want:

modelBuilder.Entity<Book>().ToTable("Book");


3. Writing a Custom Convention:

Just because EF Core RC2 does not have a convention for this, it doesn't mean we can't write our own. To do so, first we need to create an extension method on ModelBuilder object:

using Microsoft.EntityFrameworkCore.Metadata.Internal;

public static class ModelBuilderExtensions 
{
    public static void RemovePluralizingTableNameConvention(this ModelBuilder modelBuilder)
    {
        foreach (IMutableEntityType entity in modelBuilder.Model.GetEntityTypes())
        {
            entity.Relational().TableName = entity.DisplayName();
        }
    }
}

And then we simply call it from the OnModelCreating method on our DbContext object:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.RemovePluralizingTableNameConvention();
}


On Closing:

I don't like plural table names and I like the last option better than the others and went with that. That said, it's my personal opinion and other developers might find any of these 3 ways more favorable than the others and choose to go with that :)

Jamie Ide
  • 48,427
  • 16
  • 81
  • 117
Morteza Manavi
  • 33,026
  • 6
  • 100
  • 83
  • 1
    Thank you Morteza. I think that for now I'll just set the table name on the entity. – Paul Speranza May 28 '16 at 20:10
  • I also added your way to my answer so that we have them all in one place as a point of reference for other fellow developers. Thanks. – Morteza Manavi May 28 '16 at 23:48
  • Morteza - I was actually referring to using the Table attribute on the poco class but I actually like your example #2 even better because that keeps all of the setup in one spot in the context as opposed to sprinkling the attributes on each poco. – Paul Speranza May 29 '16 at 13:11
  • 1
    If you're inheriting from IdentityDbContext, make the call to `modelBuilder.RemovePluralizingTableNameConvention();` after `base.OnModelCreating(builder)` otherwise the AspNetUser tables will get mangled. – Matt Mombrea Apr 28 '17 at 20:31
  • @MattMombrea In **EF Core 2.0** calling `modelBuilder.RemovePluralizingTableNameConvention();` after `base.OnModelCreating(modelBuilder);` does not solve problem when DbContext is inherited from `IdentityDbContext`. ASP Identity table names are still mangled. – Sasa Tancev Oct 20 '17 at 13:54
  • 3
    @Tančev Saša I tried to call `modelBuilder.RemovePluralizingTableNameConvention();` before `base.OnModelCreating(builder);` and identity tables have OK names – zholinho Oct 24 '17 at 08:58
  • 5
    IMutableEntityType doesnt have Relational() method, is it changed? – Dheeraj Kumar Nov 30 '18 at 13:16
  • 5
    entity.Relational().TableName = entity.DisplayName(); not work in .net core 3 – Hamed Hajiloo Nov 30 '19 at 07:06
  • 7
    You should be able to use entity.SetTableName(entity.DisplayName()); – Radall Aug 04 '20 at 15:38
  • @MortezaManavi : Calling `modelBuilder.RemovePluralizingTableNameConvention()` causes issues when used in conjunction with `entity.ToView("MyView")`: The entity is then tagged as a table and not as a view anymore. – Olivier Leneveu Dec 07 '20 at 15:16
  • The downside to option 3 is that it overrides `EFCore.NamingConventions`. Because of this, I've decided to just use the `TableAttribute` on all my entity classes and be totally explicit about what the name should be. Seems like the only way to get what I want (snake_case, singular). – devklick Aug 17 '22 at 20:22
  • Continuing from my previous comment, I decided to stick with option 3 here, but also call [another method](https://stackoverflow.com/a/63055998/6236042) to convert the entity.DisplayName() to snake case; `entity.SetTableName(entity.DisplayName().ToSnakeCase());` – devklick Aug 17 '22 at 20:34
68

For EF Core 3.0 and above, use this to set the TableName property (because entity.Relational() no longer exist):

public static class ModelBuilderExtensions 
{
    public static void RemovePluralizingTableNameConvention(this ModelBuilder modelBuilder)
    {
        foreach (IMutableEntityType entity in modelBuilder.Model.GetEntityTypes())
        {
            if (entity.BaseType == null)
            {
                entity.SetTableName(entity.DisplayName());
            }
        }
    }
}
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
Métoule
  • 13,062
  • 2
  • 56
  • 84
  • 2
    If you use this method with an inherited entity, you'll get the error `...Only base type entity types can be mapped to a table.`. To work around this, I used the condition `if (entity.BaseType == null)`. Base classes will return `null` while inherited classes will obviously return the base type. – Kramb Jun 19 '20 at 18:50
  • @Métoule : Calling `modelBuilder.RemovePluralizingTableNameConvention()` causes issues when used in conjunction with `entity.ToView("MyView")`: The entity is then tagged as a table and not as a view anymore. – Olivier Leneveu Dec 07 '20 at 15:18
  • @Métoule please check possible issues and workarouns for EF Core 5 https://stackoverflow.com/a/65585664/1769622 – Sebastian Widz Jan 05 '21 at 21:16
  • How about .NET 6? Neither entity.Relational() nor entity.SetTableName() exists in .NET 6. – Creative Dec 06 '21 at 00:00
  • 1
    @Creative: `entity.SetTableName` exists in EF Core 6. – Métoule Dec 17 '21 at 13:59
  • 1
    Please edit the if clause, throwed an error. Replace instead: if (entity.BaseType == null). – Hagen Jan 15 '23 at 02:21
10

The EF Core version doesn't seem to support entity.DisplayName. This is a working alternative:

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    // Skip shadow types
    if (entityType.ClrType == null)
        continue;

    entityType.Relational().TableName = entityType.ClrType.Name;
}
gunr2171
  • 16,104
  • 25
  • 61
  • 88
Nullius
  • 2,607
  • 2
  • 16
  • 22
  • 4
    `entity.DisplayName` is an extension method in the `Microsoft.EntityFrameworkCore.Metadata.Internal` namespace (which is actually public, not `internal`). – hgcummings Jun 12 '18 at 14:50
9

This is also an option:

 using System.ComponentModel.DataAnnotations.Schema;

 [Table("Book")]
 public class Book
 {...}

although you need to annotate it on each entity

Sjors Miltenburg
  • 2,540
  • 4
  • 33
  • 60
  • I found myself wanting to organize via schema, so I was annotating with this tag on every class anyway. As an Example: [Table("Book", Schema = "library")] – Greg Sep 03 '21 at 11:28
6

The EF Core 5 has resolved using a switch "-NoPluralize" while updating the Db Context:

Scaffold-DbContext "..conn str.." Microsoft.EntityFrameworkCore.SqlServer -OutputDir EntityDbContext -Project DoctorsExpress.Domain -Force -NoPluralize
Sonu K
  • 2,562
  • 2
  • 20
  • 32
5

In Entity Framework NET core v2 you can choose to pluralize or singularize DbSets and Collections with a hook.

public class MyDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        services.AddSingleton<IPluralizer, MyPluralizer>();
    }
}

public class MyPluralizer : IPluralizer
{
    public string Pluralize(string name)
    {
        return Inflector.Inflector.Pluralize(name) ?? name;
    }

    public string Singularize(string name)
    {
        return Inflector.Inflector.Singularize(name) ?? name;
    }
}

See this answer for more information: https://stackoverflow.com/a/47410837/869033

Nick N.
  • 12,902
  • 7
  • 57
  • 75
0

I use this for EF Core 3.1 to preserve [Table("some_table_name")] annotation on entity types, although ConventionAnnotation is an internal class.

static class UseEntityTypeNameForTableNameExtension
{
    public static void UseEntityTypeNameForTableName(this ModelBuilder modelBuilder)
    {
        foreach (var entity in modelBuilder.Model.GetEntityTypes())
        {
            var tableNameAnnotation = (ConventionAnnotation)entity.FindAnnotation(RelationalAnnotationNames.TableName);
#pragma warning disable EF1001
            var configurationSource = tableNameAnnotation.GetConfigurationSource();
#pragma warning restore EF1001
            if (configurationSource != ConfigurationSource.Convention)
            {
                // Set explicitly using Fluent API or has TableAttribute DataAnnotation
                continue;
            }
            var defaultTableName = entity.GetDefaultTableName();
            entity.SetTableName(defaultTableName);
        }
    }
}
SeongChan Lee
  • 367
  • 2
  • 8
-2

I went with adding a virtual

public virtual DbSet<TableName> TableName{ get; set; }
public DbSet<TableName> TableNames { get; set; }

TableNames.FirstOrDefault();
notElonMusk
  • 314
  • 1
  • 4
  • 21
  • 1
    Quality username. Low quality answer. You should mention *why* you went with this approach and how it solves the problem in the description. – devklick Aug 17 '22 at 19:43