Skip to content
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

Code templates for scaffolding entity types and DbContext from an existing database #4038

Closed
Tracked by #24106 ...
rowanmiller opened this issue Dec 10, 2015 · 57 comments · Fixed by #28678
Closed
Tracked by #24106 ...
Assignees
Labels
area-scaffolding closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. ef6-parity type-enhancement
Milestone

Comments

@rowanmiller
Copy link
Contributor

We have one seam at the moment where folks can get a hold of the IModel we build from the database and manipulate it. We haven't really done any usability testing on this to see if it is good for changing table name conventions, etc..

We will also want some higher level extensibility points, such as code generation templates.

@abelepereira
Copy link

Where is this IModel manipulation being allowed? I guess some sort of extension over the default ef command (EntityFramework.Commands) need to be implemented, but where? Also: does this "extension" for model customization implies creating a new command assembly or will the default EntityFramework.Commands allow some sort of DI?

Regards

@rowanmiller
Copy link
Contributor Author

The seam we have at the moment is designed for providers to use... so yes, you probably need to implement at least some parts of the provider to use it. This issue is about creating some high level seams that can be used by the application developer.

@dazinator
Copy link

Just wanted to check my understanding - as of the present release there is no way for an application developer to customise the code generated via scaffolding (a provider writer can), although in earlier releases there was a razor based template approach which has since been pulled? So essentially to do stuff like pluralisation etc we are waiting for the resolution of this issue - is that correct?

@rowanmiller
Copy link
Contributor Author

@dazinator yes, that is correct. Post the 7.0.0 release we plan to provide customizable code-gen templates and code based interception points where you can customize the reverse engineered model and how it is written out to code.

@idg10
Copy link

idg10 commented Dec 30, 2015

One problem with this approach is that the existing model seems to support just one Name for an entity, which is used for both the generated type, and also for the property on the context. This means that if you want an entity type called Customer but and you want the DbSet<Customer> on your context to be called Customers, it doesn't look like you can do it, because the code gen pulls the name of both the type and that property from the IEntitySet.Name property.

I've worked through an attempt to singularize some names. (I'm working with a database where all the tables have plural names. Leaving this as is produces correct-sounding dbset properties, but wrong-sounding entity types. E.g., new Customers is a weird way to create a single customer. Singular names produce wrong-sounding dbset props, but I find that slightly less disturbing.)

Having done this, I'm not sure the approach of modifying the model feels right, because the name you want depends on where the name is actually being used - a property referring to a collection of entities of some type typically wants a different name than one referring to a single property, and some people might want yet another convention again for the mapped table name. I'd prefer the ability to supply an interface (e.g., INameMapper) with methods such as GetSingularNavigationPropertyName, GetMultipleNavigationPropertyName, GetEntityTypeName, and maybe even GetContextDbSetPropertyName.

There's already a partial implementation of this concept in RelationalScaffoldingModelFactory, which has GetEntityTypeName and GetPropertyName methods you can override. My ideal solution to this would have this fleshed out so I can control everything, and for it to be separated out, so that I'm not obliged to derive from, say, SqlServerScaffoldingModelFactory just to be able to plug in my logic. (Pluralizing/singularizing of identifiers used in code doesn't feel like it should have a dependency on a database-specific type, but as far as I can tell, I needed to make my own derived SqlServerScaffoldingModelFactory to be able to use this extensibility point.)

@jjwilliams42
Copy link

jjwilliams42 commented Sep 30, 2017

I realize this is going on 2 years old, but was anything changed here that might make customization easier?

@tonysneed
Copy link

👍 For providing customizable code gen templates (for ex, T4 or handlebars), but doing so in a way that can feed into dotnet ef scaffold, so that it's cross platform and not tied to Visual Studio.

@bricelam
Copy link
Contributor

bricelam commented Oct 9, 2017

No progress yet. Our main focus for Reverse Engineering is enable updating the model to incorporate changes made to the database after the initial scaffold. #831 During update, we'll try to preserve any manual changes that have been made to the model (e.g. renames and inheritance) which mitigates some of the reasons you might be asking for this feature. But there are still plenty of other reasons to do this feature. It's just a matter of prioritization.

@tonysneed
Copy link

In #9676 @ajcvickers states you would accept a PR to add virtual methods for extensibility. If that's the case, I'd be happy to submit a PR for this.

@ajcvickers
Copy link
Member

@tonysneed Yep. There was a PR (#9908) but it was abandoned. We would want protected virtual methods.

@bricelam
Copy link
Contributor

bricelam commented Oct 10, 2017

If anyone is interested in poking around the internal components...

⚠️Warning: These will break in a future release.

class MyDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
        => services
            .AddSingleton<ICSharpDbContextGenerator, MyDbContextGenerator>()
            .AddSingleton<ICSharpEntityTypeGenerator, MyEntityTypeGenerator>();
}

class MyDbContextGenerator : CSharpDbContextGenerator
{
    public MyDbContextGenerator(
        IScaffoldingProviderCodeGenerator providerCodeGenerator,
        IAnnotationCodeGenerator annotationCodeGenerator,
        ICSharpUtilities cSharpUtilities)
        : base(providerCodeGenerator, annotationCodeGenerator, cSharpUtilities)
    {
    }
    
    // TODO: Override DbContext generation
}

class MyEntityTypeGenerator : CSharpEntityTypeGenerator
{
    public MyEntityTypeGenerator(ICSharpUtilities cSharpUtilities)
        : base(cSharpUtilities)
    {
    }
    
    // TODO: Override entity type generation
}

@tonysneed
Copy link

I can pick this one up. Already signed a contrib agreement for ASPNET Core.

@tonysneed
Copy link

tonysneed commented Oct 11, 2017

For some reason adding the user profile dotnet folder to my path system env variable doesn't seem to work.

env-var-local-dotnet

dotnet --version doesn't see it.

dotnet-version

However, if I replace the path entirely, it's OK.

dotnet-version-ok

Am I doing something obviously wrong? TIA!

P.S. I can just open the VS solution from the command line, so I can get past the issue. Just wondering about setting the global path and what I might be doing wrong there.

@tonysneed
Copy link

tonysneed commented Oct 11, 2017

@bricelam So to use the overrides, would one then register IDesignTimeServices with MyDesignTimeServices in Startup.ConfigureServices?

nm .. I see how to do it in your SO answer here.

@bricelam
Copy link
Contributor

That answer outdated. Just add an implementation anywhere in your project. The tools will scan the assembly to find it.

@ajcvickers
Copy link
Member

@tonysneed Make sure the userprofile dotnet is at the start of the path so that it is found before the normally installed copy.

@bricelam
Copy link
Contributor

Also, don't use %USERPROFILE% in System variables. It's ...unpredictable. 😉

@tonysneed
Copy link

@ajcvickers I'm having a hard time controlling the placement of the userprofile dotnet in the path. Adding it at the top ..

env-var-local-dotnet2

Seems to have no effect. It is placed after the system dotnet.

sys-path

Not a big deal, since I can set the path on the command line and open VS from there. Just curious if I'm missing something obvious.

@ErikEJ
Copy link
Contributor

ErikEJ commented Oct 11, 2017

I have removed the system .net path setting

@ajcvickers
Copy link
Member

@tonysneed I think you need to set it as a system environment variable--at least, that's what I did. You can also click on Edit text.., then it's easy to put it where you want:
image

@tonysneed
Copy link

tonysneed commented Oct 11, 2017

OK, mystery solved. I was opening the command prompt from the GitHub Desktop app, and it wasn't picking up the new environment variables -- until I restarted the app.

bricelam added a commit to bricelam/efcore that referenced this issue Mar 15, 2022
bricelam added a commit to bricelam/efcore that referenced this issue Jul 1, 2022
bricelam added a commit to bricelam/efcore that referenced this issue Jul 11, 2022
bricelam added a commit to bricelam/efcore that referenced this issue Jul 29, 2022
This refactors our existing scaffolding code into T4 templates that we can both precompile to use as our default code generator and also ship somehow (probably `dotnet new`) as a starting point for users to start customizing.

Part of dotnet#4038, part of dotnet#14545, fixes dotnet#25473, resolves dotnet#25546, resolves dotnet#25547, fixes dotnet#27087, part of dotnet#27588, fixes dotnet#28187
bricelam added a commit to bricelam/efcore that referenced this issue Aug 1, 2022
This refactors our existing scaffolding code into T4 templates that we can both precompile to use as our default code generator and also ship somehow (probably `dotnet new`) as a starting point for users to start customizing.

Part of dotnet#4038, part of dotnet#14545, fixes dotnet#25473, resolves dotnet#25546, resolves dotnet#25547, fixes dotnet#27087, part of dotnet#27588, fixes dotnet#28187
bricelam added a commit to bricelam/efcore that referenced this issue Aug 8, 2022
This refactors our existing scaffolding code into T4 templates that we can both precompile to use as our default code generator and also ship somehow (probably `dotnet new`) as a starting point for users to start customizing.

Part of dotnet#4038, part of dotnet#14545, fixes dotnet#25473, resolves dotnet#25546, resolves dotnet#25547, fixes dotnet#27087, part of dotnet#27588, fixes dotnet#28187
bricelam added a commit to bricelam/efcore that referenced this issue Aug 9, 2022
This refactors our existing scaffolding code into T4 templates that we can both precompile to use as our default code generator and also ship somehow (probably `dotnet new`) as a starting point for users to start customizing.

Part of dotnet#4038, part of dotnet#14545, fixes dotnet#25473, resolves dotnet#25546, resolves dotnet#25547, fixes dotnet#27087, part of dotnet#27588, fixes dotnet#28187
bricelam added a commit to bricelam/efcore that referenced this issue Aug 11, 2022
Adds a new package that can be installed via `dotnet new`:

    dotnet new install Microsoft.EntityFrameworkCore.Templates::7.0.0-*

For now, it just includes a single item template that will add the default T4 templates used by `dotnet ef dbcontext scaffold`.

    dotnet new ef-templates

You can then tweak the templates and they'll automatically be used when scaffolding.

    dotnet ef dbcontext scaffold Filename=northwind.db Microsoft.EntityFrameworkCore.Sqlite

Resolves dotnet#4038
@bricelam bricelam added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Aug 11, 2022
@bricelam bricelam modified the milestones: 7.0.0, 7.0.0-rc1 Aug 11, 2022
@ghost ghost closed this as completed in #28678 Aug 11, 2022
ghost pushed a commit that referenced this issue Aug 11, 2022
Adds a new package that can be installed via `dotnet new`:

    dotnet new install Microsoft.EntityFrameworkCore.Templates::7.0.0-*

For now, it just includes a single item template that will add the default T4 templates used by `dotnet ef dbcontext scaffold`.

    dotnet new ef-templates

You can then tweak the templates and they'll automatically be used when scaffolding.

    dotnet ef dbcontext scaffold Filename=northwind.db Microsoft.EntityFrameworkCore.Sqlite

Resolves #4038
@ajcvickers ajcvickers modified the milestones: 7.0.0-rc1, 7.0.0 Nov 5, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-scaffolding closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. ef6-parity type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.