Skip to content

Discussion for Announcement 167: Table names now taken from DbSet names (starting in RC2) #4996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ericwj opened this issue Apr 6, 2016 · 27 comments
Milestone

Comments

@ericwj
Copy link

ericwj commented Apr 6, 2016

Where is the comments/discussion link for EF Core: Table names now taken from DbSet names (starting in RC2) Or I'll just drop my thought on this right here:

Kudos @rowanmiller & team for this, it's great!

It always felt like there was some hard to understand reason why this couldn't be done or some data modelling purists didn't want it and truth be told I've not thought of asking for this in EF7, but now finally this is really going to be as intuitive as many people probably thought with me it could be.

Correct me if I'm wrong, I believe EF has always had these complex mapping strategies and pluralization etc while the property of the DbContext is there most of the time, pluralized and spelled correctly for EF to just use.

@divega divega added this to the Discussions milestone Apr 6, 2016
@divega divega changed the title Where is the comments/discussion link for Announcement 167? Discussion for Announcement 167: Table names now taken from DbSet names (starting in RC2) Apr 6, 2016
@PhillipVoyle
Copy link

Will the [Key] attribute still be respected?

@miguellira
Copy link

@PhillipVoyle Did you mean the [Table] attribute? I can't see how this change would impact the naming of Keys.

@miguellira
Copy link

@divega Does this affect the naming of objects created by EF in a many to many scenario?

@divega
Copy link
Contributor

divega commented Apr 6, 2016

@PhillipVoyle @miguellira I don't think [Key] is affected, although I may be missing something. [Table] should continue to work as a way to explicitly pick a name explicitly.

Does this affect the naming of objects created by EF in a many to many scenario?

EF Core currently doesn't support modeling many-to-many directly without a link entity type. The name of the table for that link entity type will follow the same rules as any other entity type, e.g. the table will be named after the type unless there is a DbSet for it in the context, the name is specified using [Table] fluent or metadata APIs.

@miguellira
Copy link

@divega Thanks for the quick response. So for the following model: http://docs.efproject.net/en/latest/modeling/relationships.html#many-to-many

Since the link entity type is not exposed as a DbSet you would end up with dbo.Posts, dbo.Tags, and dbo.PostTag... not the plural form dbo.PostTags - correct?

@divega
Copy link
Contributor

divega commented Apr 6, 2016

@miguellira Yes, I would expect dbo.PostTag to be the table name in this case.

@divega
Copy link
Contributor

divega commented Apr 6, 2016

Correct me if I'm wrong, I believe EF has always had these complex mapping strategies and pluralization etc while the property of the DbContext is there most of the time, pluralized and spelled correctly for EF to just use.

@ericwj Yes, I think that synthesizes very well our thinking on this: With this improvement EF Core can leverage naming choices made by the developer instead of being in the business of processing the words and producing plurals for table names in a specific language (we did that in Code First for previous versions of EF and it turned out to be a dead end, especially since any bug fix on the pluralizer becomes a breaking change in the runtime). Design-time/reverse engineering tooling is a different story. We may still add something there: #3060.

@entitycontext
Copy link

As someone who prefers singular table names but likes plural DbSet names, I disagree with this approach. In my opinion, having the PluralizingTableNameConvention as a default in previous EF versions was a mistake and I would prefer to see that removed as a default while keeping table names the same as class names.

Apologies for bikeshedding and maybe I am just out of step with industry practices, but it seems to me far more common that people use singular table names in SQL, while plural DbSet names match better with C# conventions.

@miguellira
Copy link

@entitycontext I generally agree with you. The singular/plural table name is a matter of personal preference and the singular form is often chosen to avoid dealing with irregular plurals (e.g. person/people).

That said, I think the EF teams wants to avoid that issue by defaulting to a name that you have chosen in your model that should make sense in your database.

Fortunately, if it doesn't sit well with you, you can always override it via attributes or fluent definitions.

BTW, other technologies (like Ruby/Rails/ActiveRecord) defaults to plural form so "industry practices" will vary by the technologies chosen. 😃

@entitycontext
Copy link

@miguellira I agree it really is just a matter of personal preference, but it's annoying to have to fight against the defaults when you don't agree with them. See also: LazyLoadingEnabled and OneToManyCascadeDeleteConvention in EF6, both of which I strongly prefer to have turned off and also arguably should be off by default.

Since I want singular table names, I will consider using singular DbSet names as well for new projects in EF Core rather than fighting against the default behavior in the model builder. Honestly, that wouldn't be a terrible thing and might even be better for mentally switching between SQL and LINQ - would just feel weird at first, since I've been pluralizing the DbSet names for so long.

@miguellira
Copy link

@entitycontext If you're the only one that will be working on that code do what works for you and keeps you happy. However, if you expect others to see something like:

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

when they're used to seeing something like:

public DbSet<Person> People { get; set; }

and not question your approach... be prepared to do some explaining. 😃

@ericwj
Copy link
Author

ericwj commented Apr 11, 2016

There is a two-liner in the announcement however that you could tweak a little to change all table names to the type name and keep the People property name too.

@grahamehorner
Copy link

will there be an option to allow the entity/table to be in a different schema other than dbo ?

@miguellira
Copy link

@grahamehorner Maybe I'm missing something but that's always been there. You can use modelbuilder.HasDefaultSchema() or the overload on ToTable()

@rigofunc
Copy link

rigofunc commented Apr 20, 2016

@rowanmiller
public class Blogging : DbContext
{
public DbSet<Blog> Blog_One { get; set; }
public DbSet<Blog> Blog_Two { get; set; }
...
}

public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}

Could I have two same structure tables? one table named Blog_One another table named Blog_Two

@gdoron
Copy link

gdoron commented Apr 20, 2016

@xyting Sounds like a bad design to me.
What is the actual problem you're trying to solve here?

@anpete
Copy link
Contributor

anpete commented Apr 20, 2016

@xyting You would need two different context types for that. At a very high level, EF operations are keyed on the CLR type, and so a single CLR type can only map to one table (currently).

@gdoron
Copy link

gdoron commented Apr 20, 2016

@xyting but why not just add another property-column with the tenant name? (I guess you are trying to solve multi tenancy here) or other solutions like that.

@laskoviymishka
Copy link
Contributor

laskoviymishka commented May 13, 2016

EF use convention over configuration, which is good. But this option is not quite support any extensibility.
What if there be some convention strategy that can be applied? I.e. we could introduce this change somewhere on configuration level, instead of do some dirty hacks, or mark everything with attributes:

foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
    entity.Relational().TableName = entity.DisplayName();
}

We could use something more suited (in db context or in service configure section).
Let's imagine we have ITableNamingConvention, which have basically 2 implementation - EntityNamingConvention and DbSetNamingConvention. By default we register DbSetNamingConvention, but user could easily configure this behaivior with following code

public void ConfigureServices(IServiceCollection services)
 {
            // bla-bla boring configuration
            services.AddEntityFramework()
                .AddNamingConvention<EntityNamingConvention>() // convention setup
                .AddSqlServer();
}

This is pretty important stuff IMHO. Lets imaging that you have some really big old fashioned enterprise. You wanna adopt new technologies, and business give you green light with .net core. But it only for server side. DB part still need to follow certain standarts, including specific naming convention.
This is pretty boring to mark every of 250 tables/entities in project with Table attribute, but you know the rule how this naming convention applied. Well let it be so - if this entity inherit from interface A you do C_ prefix, when interface B L_ prefix and interfacr C with R_ prefix after this upper case class name and so on. Pretty strict rule. Right now there is no option to add this smoothly in EF (at least i cant find it 😅).
Poor guy was already despaired, but suddenly he find out about our imaginary ITableNamingConvention, which provide point of extensibiliy for such feature.
He implement this naming rule interface, and register custom convention:

public void ConfigureServices(IServiceCollection services)
 {
            // bla-bla boring configuration
            services.AddEntityFramework()
                .AddNamingConvention<OracleNamingConvention>() // convention setup
                .AddSqlServer();
}

_BOOM_
asd

Everyone happy 👍
Any thoughts on this?
This is not really hard to implement, if you okay with this i could provide PR.

@rowanmiller
Copy link
Contributor

@laskoviymishka

This is pretty boring to mark every of 250 tables/entities in project with Table attribute, but you know the rule how this naming convention applied. Well let it be so - if this entity inherit from interface A you do C_ prefix, when interface B L_ prefix and interfacr C with R_ prefix after this upper case class name and so on. Pretty strict rule. Right now there is no option to add this smoothly in EF (at least i cant find it 😅).

You can do this in OnModelCreating, using similar code to the snippet you posted that applies the RC1 naming convention. This is similar to the conventions we have in EF6.x - except that in EF Core we no longer need a special object model to store conventions since the model is already built and you can just directly manipulate it in OnModelCreating.

We do also have the concept of conventions in EF Core, and providers can already register custom conventions. In fact, getting the table name from DbSet is already a convention that is registered when you use a relational database provider - see TableNameFromDbSetConvention.

I'm not sure we want to start exposing granular model building things on context configuration, we already have a special method that deals exclusively with model building OnModelCreating.

@laskoviymishka
Copy link
Contributor

@rowanmiller yes i can do this in OnModelCreating but this really looks like ducktape 😅 .

Regards to TableNameFromDbSetConvention my bad, not mentioned this 😓
If so my proposal little bit changed - what if we just add another implementation of IBaseTypeConvention for old convention? This will be more natural way to change naming. And will not broke anything.

@RickyLin
Copy link
Contributor

RickyLin commented May 19, 2016

entity.DisplayName() doesn't get the correct table name if the entity type has TableAttribute, it just gets the class name.

@rowanmiller
Copy link
Contributor

@RickyLin good point, here is some more complex code that sets the table name the same way our "get the name from the DbSet property" convention works...

var internalBuilder = modelBuilder.GetInfrastructure<InternalModelBuilder>();
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
    internalBuilder
        .Entity(entity.Name, ConfigurationSource.Convention)
        .Relational(ConfigurationSource.Convention)
        .ToTable(entity.ClrType.Name);
}

@crozone
Copy link

crozone commented Jun 7, 2016

Forgive me if I'm missing something obvious, but I've ported my asp net app from RC1 to RC2 (using all 1.0.0-preview1-final EF bits), and I'm still getting the old table naming convention, despite deleting all migrations and starting again from scratch. Additionally, dotnet ef migrations add keeps creating a .\Migrations folder and adding migrations to that, rather than adding them to the .\Data\Migrations folder.

The default new RC2 MVC new project that VS creates works as expected, and I used it as a reference for porting my app (the .xproj, project.json, and launchSettings.json are pretty much identical). dotnet ef --version yields 1.0.0-preview-20901 for both. Is there some hidden configuration I'm missing that enables the new behaviour?

EDIT: Found the issue. The Npgsql database provider seems to not implement, or overrides, the new behaviour. I'll take this issue over to npgsql. In the meantime, is there any code that will force the naming convention to the new style, avoiding a potentially painful migration in the future?

EDIT Nevermind X2, found the pull request for the change. The code is slightly too involved to comfortably cram into the OnModelCreating method as a workaround. Migrations appear to handle the table name change safely, so it should be safe to wait it out.

@bryanjhogan
Copy link

Are you planning to introduce a pluralization option as was there in EF 6 and earlier versions.

This change is quite inconvenient for those of us with large amounts of code built on RC1

@divega
Copy link
Contributor

divega commented Nov 24, 2016

@bryanjhogan if you need to keep the table names the same as they were before, consider using the workaround detailed at #4996 (comment).

We are going to consider using plularization and sigularization for database reverse engineering in the future but we don't want to depend on pluralization to decide the names of tables at runtime. We did that in EF6 and it turned out to be less than ideal, e.g. once we did that, fixing bugs in pluralization would become breaking changes on the runtime.

@ajcvickers
Copy link
Contributor

We are closing this issue because no further action is planned for this issue. If you still have any issues or questions, please log a new issue with any additional details that you have.

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests