Code Monkey home page Code Monkey logo

entityframeworkcore.scaffolding.handlebars's Introduction

Entity Framework Core Scaffolding with Handlebars

Scaffold EF Core models using Handlebars templates.

EF Core Community Standup

View the EF Core Community Standup episode featuring this framework for scaffolding entities with Handlebars templates. The demos for the episode can be found on this GitHub repo.

Contributing

Before creating a pull request, please refer to the Contributing Guidelines.

Prerequisites

Windows Intel Setup

  • Use SQL Server Management Studio to connect to SQL Server
  • The easiest is to use LocalDb, which is installed with Visual Studio.
  • Connect to: (localdb)\MsSqlLocalDb.
  • Create a new database named NorthwindSlim.
  • Download the NorthwindSlim.sql file from https://github.com/TrackableEntities/northwind-slim.
  • Unzip NorthwindSlim.sql and run the script to create tables and populate them with data.

MacOS arm64 Setup (M Series)

docker run -e "ACCEPT_EULA=1" -e "MSSQL_SA_PASSWORD=MyPass@word" -e "MSSQL_PID=Developer" -e "MSSQL_USER=SA" -p 1433:1433 -d --name=sql mcr.microsoft.com/azure-sql-edge
  • Add VS Code Extension for SQL Server
    • Connect with username sa and password MyPass@word
    • Enable trust server certificate when prompted
    • See here for help connecting and writing commands and queries
  • Create a new database named NorthwindSlim.
  • Download the NorthwindSlim.sql file from https://github.com/TrackableEntities/northwind-slim.
  • Unzip NorthwindSlim.sql and run the script to create tables and populate them with data.

Upgrading

  1. Upgrade TargetFramework in .csproj file to net8.0.
    • Optional: Set ImplicitUsings to enable.
    • Optional: Set Nullable to enable.
  2. Update the following NuGet packages to 8.0.0 or later:
    • Microsoft.EntityFrameworkCore.Design
    • Microsoft.EntityFrameworkCore.SqlServer
    • EntityFrameworkCore.Scaffolding.Handlebars
  3. Remove the EnableNullableReferenceTypes option from services.AddHandlebarsScaffolding in ScaffoldingDesignTimeServices.ConfigureDesignTimeServices.
  4. Run dotnet ef dbcontext scaffold command to regenerate entities.
    • You may retain your customized Handlebars templates.
    • Many-to-many relationships will be materialized without the need for an intermediate entity.

Usage

  1. Create a new .NET 8 class library.

  2. Add EF Core SQL Server and Tools NuGet packages.

    • Microsoft.EntityFrameworkCore.SqlServer
    • Microsoft.EntityFrameworkCore.Design
    dotnet add package Microsoft.EntityFrameworkCore.SqlServer
    dotnet add package Microsoft.EntityFrameworkCore.Design
    
  3. Add the EntityFrameworkCore.Scaffolding.Handlebars NuGet package:

    • EntityFrameworkCore.Scaffolding.Handlebars
    dotnet add package EntityFrameworkCore.Scaffolding.Handlebars
    
  4. Remove Class1.cs and add a ScaffoldingDesignTimeServices class.

    • Implement IDesignTimeServices by adding a ConfigureDesignTimeServices method that calls services.AddHandlebarsScaffolding.
    • You can optionally pass a ReverseEngineerOptions enum to indicate if you wish to generate only entity types, only a DbContext class, or both (which is the default).
    public class ScaffoldingDesignTimeServices : IDesignTimeServices
    {
        public void ConfigureDesignTimeServices(IServiceCollection services)
        {
            services.AddHandlebarsScaffolding();
        }
    }
  5. Open a command prompt at the project level and use the dotnet ef tool to reverse engineer a context and models from an existing database.

    • Get help on dotnet-ef-dbcontext-scaffold at the command line: dotnet ef dbcontext scaffold -h
    • Execute the following command to reverse engineer classes from the NorthwindSlim database:
    dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=NorthwindSlim; Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer -o Models -c NorthwindSlimContext -f --context-dir Contexts
    
    • You should see context and/or entity classes appear in the Models folder of the project.
    • You will also see a CodeTemplates folder appear containing Handlebars templates for customizing generation of context and entity type classes.
    • Add -d to the command to use data annotations. You will need to add the System.ComponentModel.Annotations package to a .NET Standard library containing linked entity classes.
  6. You may edit any of the template files which appear under the CodeTemplates folder.

    • For now you can just add some comments, but you may wish to customize the templates in other ways, for example, by inheriting entities from a base class or implementing specific interfaces.
    • When you run the dotnet-ef-dbcontext-scaffold command again, you will see your updated reflected in the generated classes.

Nullable Reference Types

Take advantage of C# nullable reference types by enabling them in your .csproj file. (This is by default in .NET 6 or greater.)

<PropertyGroup>
  <TargetFramework>net6.0</TargetFramework>
  <Nullable>enable</Nullable>
</PropertyGroup>

Non-nullable properties will include the null forgiving operator.

public partial class Product
{
    public string ProductName { get; set; } = null!;
    public decimal? UnitPrice { get; set; }
}

Excluded Tables

You can optionally exclude certain tables from code generation. These may also be qualified by schema name.

services.AddHandlebarsScaffolding(options =>
{
    // Exclude some tables
    options.ExcludedTables = new List<string> { "dbo.Territory" };
});

Custom Template Data

You may find it useful to add your own custom template data for use in your Handlebars templates. For example, the model namespace is not included by default in the DbContext class import statements. To compensate you may wish to add a models-namespace template to the DbImports.hbs template file.

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata; // Comment
using {{models-namespace}};

Likewise you may wish to specify the name of a model base class in the same way.

public partial class {{class}} : {{base-class}}
{
    {{{> constructor}}}
    {{> properties}}
}

You can then set the value of these templates in the TemplateData property of HandlebarsScaffoldingOptions.

services.AddHandlebarsScaffolding(options =>
{
    // Add custom template data
    options.TemplateData = new Dictionary<string, object>
    {
        { "models-namespace", "ScaffoldingSample.Models" },
        { "base-class", "EntityBase" }
    };
});

Schema Folders

You can generate models in different folders by database schema.

services.AddHandlebarsScaffolding(options =>
{
    // Put Models into folders by DB Schema
    options.EnableSchemaFolders = true;
});

Embedded Templates

Handlebars templates may be embdedded in a separate .NET Standard project that can be shared among multiple .NET Core scaffolding projects. Simply copy the CodeTemplates folder to the .NET Standard project and edit the .csproj file to embed them as a resource in the assembly.

<ItemGroup>
  <EmbeddedResource Include="CodeTemplates\**\*.hbs" />
</ItemGroup>

Then reference the .NET Standard project from the .NET Core projects and specify the templates assembly when adding Handlebars scaffolding in the ScaffoldingDesignTimeServices class.

public class ScaffoldingDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        // Get templates assembly
        var templatesAssembly = Assembly.Load("TemplatesAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

        // Add Handlebars scaffolding using embedded templates templates
        services.AddHandlebarsScaffolding(options => options.EmbeddedTemplatesAssembly = templatesAssembly);
    }
}

Handlebars Helpers and Transformers

You can register Handlebars helpers in the ScaffoldingDesignTimeServices where setup takes place.

  • Create a named tuple as shown with myHelper below.
  • The context parameter of the helper method provides model data injected by the Handlebars scaffolding extension.
  • Pass the tuple to the AddHandlebarsHelpers extension method.
  • To use Handlebars helper defined above, add the following to any of the .hbs files within the CodeTemplates folder: {{my-helper}}
  • You may register as many helpers as you wish.

You can pass transform functions to AddHandlebarsTransformers in order to customize generation of entity type definitions, including class names, constructors and properties.

public class ScaffoldingDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        // Add Handlebars scaffolding templates
        services.AddHandlebarsScaffolding(options =>
        {
            // Generate both context and entities
            options.ReverseEngineerOptions = ReverseEngineerOptions.DbContextAndEntities;

            // Enable Nullable reference types
            options.EnableNullableReferenceTypes = true;

            // Put Models into folders by DB Schema
            //options.EnableSchemaFolders = true;

            // Exclude some tables
            options.ExcludedTables = new List<string> { "Territory", "EmployeeTerritories" };

            // Add custom template data
            options.TemplateData = new Dictionary<string, object>
            {
                { "models-namespace", "ScaffoldingSample.Models" },
                { "base-class", "EntityBase" }
            };
        });

        // Register Handlebars helper
        var myHelper = (helperName: "my-helper", helperFunction: (Action<TextWriter, Dictionary<string, object>, object[]>) MyHbsHelper);

        // Add optional Handlebars helpers
        services.AddHandlebarsHelpers(myHelper);

            // Add Handlebars transformer for Country property
            services.AddHandlebarsTransformers(
                propertyTransformer: p =>
                    p.PropertyName == "Country"
                        ? new EntityPropertyInfo("Country?", p.PropertyName, false)
                        : new EntityPropertyInfo(p.PropertyType, p.PropertyName, p.PropertyIsNullable));

            // Add Handlebars transformer for Id property
            //services.AddHandlebarsTransformers2(
            //    propertyTransformer: (e, p) =>
            //        $"{e.Name}Id" == p.PropertyName
            //            ? new EntityPropertyInfo(p.PropertyType, "Id", false)
            //            : new EntityPropertyInfo(p.PropertyType, p.PropertyName, p.PropertyIsNullable));

            // Add optional Handlebars transformers
            //services.AddHandlebarsTransformers2(
            //    entityTypeNameTransformer: n => n + "Foo",
            //    entityFileNameTransformer: n => n + "Foo",
            //    constructorTransformer: (e, p) => new EntityPropertyInfo(p.PropertyType + "Foo", p.PropertyName + "Foo"),
            //    propertyTransformer: (e, p) => new EntityPropertyInfo(p.PropertyType, p.PropertyName + "Foo"),
            //    navPropertyTransformer: (e, p) => new EntityPropertyInfo(p.PropertyType + "Foo", p.PropertyName + "Foo"));
    }

    // Sample Handlebars helper
    void MyHbsHelper(TextWriter writer, Dictionary<string, object> context, object[] parameters)
    {
        writer.Write("// My Handlebars Helper");
    }
}

Extending the OnModelCreating Method

There are times when you might like to modify generated code, for example, by adding a HasConversion method to an entity property in the OnModelCreating method of the generated class that extends DbContext. However, doing so may prove futile because added code would be overwritten the next time you run the dotnet ef dbcontext scaffold command.

  • Rather than modifying generated code, a better idea would be to extend it by using partial classes and methods. To enable this scenario, the generated DbContext class is already defined using the partial keyword, and it contains a partial OnModelCreatingPartial method that is invoked at the end of the OnModelCreating method.
  • To implement the partial method, simply add a new class to your project with the same name as the generated DbContext class, and define it as partial. Then add a OnModelCreatingPartial method with the same signature as the partial method defined in the generated DbContext class.
// Place in separate class file (NorthwindSlimContextPartial.cs)
public partial class NorthwindSlimContext
{
    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Employee>()
            .Property(e => e.Country)
            .HasConversion(
                v => v.ToString(),
                v => (Country)Enum.Parse(typeof(Country), v));

        modelBuilder.Entity<Customer>()
            .Property(e => e.Country)
            .HasConversion(
                v => v.ToString(),
                v => (Country)Enum.Parse(typeof(Country), v));
    }
}

Generating TypeScript Entities

To generate TypeScript entities simply pass LanguageOptions.TypeScript to AddHandlebarsScaffolding. Since generating a DbContext class is strictly a server-side concern, you should also pass ReverseEngineerOptions.EntitiesOnly to AddHandlebarsScaffolding.

public class ScaffoldingDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        // Generate entities only
        var options = ReverseEngineerOptions.EntitiesOnly;

        // Generate TypeScript files
        var language = LanguageOptions.TypeScript;

        // Add Handlebars scaffolding templates
        services.AddHandlebarsScaffolding(options, language);
    }
}

Taking Full Control by Extending Handlebars Generators

For an example of this approach, see MyHbsCSharpEntityTypeGenerator in the ef-core-community-handlebars repo.

To take full control of context and entity generation, you can extend HbsCSharpDbContextGenerator and HbsCSharpEntityTypeGenerator, overriding select virtual methods. Then register your custom generators in ScaffoldingDesignTimeServices.ConfigureDesignTimeServices.

For example, you may want to add property-isprimarykey to the template data in order to insert some code or a comment.

  1. Add a MyHbsCSharpEntityTypeGenerator to the .Tooling project.
    • Extend HbsCSharpEntityTypeGenerator.
    • Override GenerateProperties.
    • Copy code from the base GenerateProperties method.
    • Add code that inserts property-isprimarykey into the template data.
    protected override void GenerateProperties(IEntityType entityType)
    {
       var properties = new List<Dictionary<string, object>>();
       foreach (var property in entityType.GetProperties().OrderBy(p => p.GetColumnOrdinal()))
       {
          // Code elided for clarity
          properties.Add(new Dictionary<string, object>
          {
                { "property-type", propertyType },
                { "property-name", property.Name },
                { "property-annotations",  PropertyAnnotationsData },
                { "property-comment", property.GetComment() },
                { "property-isnullable", property.IsNullable },
                { "nullable-reference-types", _options?.Value?.EnableNullableReferenceTypes == true },
    
                // Add new item to template data
                { "property-isprimarykey", property.IsPrimaryKey() }
          });
       }
    
       var transformedProperties = EntityTypeTransformationService.TransformProperties(properties);
    
       // Add to transformed properties
       for (int i = 0; i < transformedProperties.Count ; i++)
       {
          transformedProperties[i].Add("property-isprimarykey", properties[i]["property-isprimarykey"]);
       }
    
       TemplateData.Add("properties", transformedProperties);
    }
  2. Register MyHbsCSharpEntityTypeGenerator in ScaffoldingDesignTimeServices.ConfigureDesignTimeServices.
    services.AddSingleton<ICSharpEntityTypeGenerator, MyHbsCSharpEntityTypeGenerator>();
  3. Update CSharpEntityType/Partials/Properties.hbs to add property-isprimarykey.
    {{#if property-isprimarykey}} // Primary Key{{/if}}
  4. Run the dotnet ef dbcontext scaffold command from above.

entityframeworkcore.scaffolding.handlebars's People

Contributors

acecoderlaura avatar bdelmeire avatar codingdna2 avatar dmayhak avatar erikej avatar illumen avatar johngoldinc avatar kevin-in-code avatar markatramp51 avatar mwmccallum avatar rich-ott avatar tonysneed avatar varorbc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

entityframeworkcore.scaffolding.handlebars's Issues

Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4.0.3.0,...

I'm using efcore 2.2.3 and requires System.Diagnostics.DiagnosticSource >= 4.5.0

System.IO.FileLoadException: Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4. 0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) File name: 'System.Diagnostics.DiagnosticSource, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2 ddd51' at Microsoft.EntityFrameworkCore.Design.DesignTimeServiceCollectionExtensions.AddEntityFrameworkDesignTime Services(IServiceCollection services, IOperationReporter reporter, Func1 applicationServiceProviderAccessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.Build(String provider)
at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, Strin
g connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schem as, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String conn
ectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFil ters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseName
s)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0
()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.b_
_0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4.0.3.0, Culture=neutral, Publi
cKeyToken=cc7b13ffcd2ddd51'. The located assembly's manifest definition does not match the assembly reference
. (Exception from HRESULT: 0x80131040)
`

[Bug] Transformers work incorrectly.

Steps to replicate:
Add transformers
services.AddHandlebarsTransformers( navPropertyTransformer: e => new EntityPropertyInfo("prefix" +e.PropertyType, e.PropertyName), entityNameTransformer: n => "prefix" + n, entityFileNameTransformer: n => "prefix" + n);

Scaffold.

Observe issues in entity constructors:
public Cat() { Paws = new HashSet<Paw>(); }

Note that new HashSet() is incorrect since entity should have "prefixPaw" type.

Doesn't seem to work with .NET Standard

And I realize that the instructions say to create a .NET Core dll, but I prefer .NET Standard if my assembly isn't a .NET Core web app. I typically have an API (.NET Core) project and a Data (.NET Standard) project and if I need scaffolding or data migrations, I just point to the API project as the start up. So this is more of a feature request. Or am I doing something wrong?

Unable to resolve service for type IHbsBlockHelperService (NETCORE 2.2, VS2019)

Hi,
I'm recently update my solution from .NET Core 2.1 to 2.2. I even updated Visual Studio from 2017 to 2019. Now, trying to scaffold my database with:
Scaffold-DbContext "data source=XXX;initial catalog=YYY;user id=ZZZ;password=QQQ;" Microsoft.EntityFrameworkCore.SqlServer -outputdir Models -context DatabaseContext -force -contextdir Contexts -DataAnnotations

I'm receiving this error:

Unable to resolve service for type 'EntityFrameworkCore.Scaffolding.Handlebars.IHbsBlockHelperService' while attempting to activate 'EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator'.

The full stack trace:

System.InvalidOperationException: Unable to resolve service for type 'EntityFrameworkCore.Scaffolding.Handlebars.IHbsBlockHelperService' while attempting to activate 'EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

This is my ScaffoldingDesignTimeServices:

public class ScaffoldingDesignTimeServices : IDesignTimeServices
{
	public void ConfigureDesignTimeServices(IServiceCollection services)
	{
		services.AddHandlebarsScaffolding(ReverseEngineerOptions.DbContextAndEntities);
	}
}

Finally, this is my csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
	<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
    <PackageId>CUT</PackageId>
    <Version>1.1.0</Version>
    <Authors>CUT</Authors>
    <Company>CUT</Company>
    <Product>CUT</Product>
    <Copyright>CUT</Copyright>
    <AssemblyVersion>1.1.0.863</AssemblyVersion>
    <FileVersion>1.1.0.863</FileVersion>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <LangVersion>7.3</LangVersion>
    <DefineConstants>TRACE;DEBUG;NETCOREAPP;NETCOREAPP2_1</DefineConstants>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <LangVersion>7.3</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="EntityFrameworkCore.Scaffolding.Handlebars" Version="2.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.4" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
  </ItemGroup>
</Project>

Can anyone help me please?

Extend OnModelCreating with Partial Method

This library is the bomb! This has greatly simplified my database-first workflow. Thank you!

I want to add some code at the end of the generated OnModelCreating function (to deal with DateTime kinds). Is there a way to add that to the template? In DbContext.hbs I see {{{on-model-creating}}}, but I'm not clear on if there's a way to extend or add to that.

Or is there a way to add a .HasConversion line to every generated DateTime field?

a couple of questions?

hi,

first and simple, is there any way of debugging this? i couldn't find any way... :(

second, i want to create views and webapis, for simple crud pages, could i use this for that purpose?

regards.

[Feature] Customize Classnames

In some cases the database tables are prefixed with something like "tbl" it would be nice to remove this kind of prefixed in the classname of the generated entities.

NullReferenceException in CheckOutputFiles

I'm using .NET Core 2.1.300-rc1-008673 and have updated to 1.0.0-rc3 of EntityFrameworkCore.Scaffolding.Handlebars. I get the following NullPointer when trying to scaffold from an existing database. I have previously used 1.0.0-beta together with .NET Core 2.0 and have successfully scaffolded using the same database.

Unable to generate entity type for table 'dbo.SavedRadioButtons'.
The column 'dbo.NoteResources.IsActive' would normally be mapped to a non-nullable bool property, but it has a default constraint. Such a column is mapped to a nullable bool property to allow a difference between setting the property to false and invoking the default constraint. See https://go.microsoft.com/fwlink/?linkid=851278 for details.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.CheckOutputFiles(ScaffoldedModel scaffoldedModel, String outputDir, Boolean overwriteFiles)
at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.Save(ScaffoldedModel scaffoldedModel, String outputDir, Boolean overwriteFiles)
at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Object reference not set to an instance of an object.

I'm using the following command:

dotnet ef dbcontext scaffold "Data Source=localhost;Initial Catalog=MyDatabase;User Id=secret; Password=secret" Microsoft.EntityFrameworkCore.SqlServer -o Domain -c MyDbContext -f

[Feature request] Have a way to know that a property is part of the object identifier (PK)

During TypeScript entities generation, I need to know if a property is part of the object identifier.

I need to tell serializr by specifiying:

identifier(): Serialize a field as primitive value, use it as identifier when serializing references (see reference)

Each navigation property is already always a reference.

It seems that this information may be available during csharp entities generation.

I'll be happy to make a pull request for that feature.
Any further guidance would be very welcome.

How to check table name in propertyTransformer

Hi,

Thanks for this great library.

Taking the example you've given in the README, is there a way to detect the table it's running on?

services.AddHandlebarsTransformers( propertyTransformer: e => e.PropertyName == "Country" ? new EntityPropertyInfo("Country", e.PropertyName) : new EntityPropertyInfo(e.PropertyType, e.PropertyName));

The problem I'm having is I have a property named Type in multiple tables and I want to change the property type depending on which class/table it is on.

Is this possible using propertyTransformer or is there another way to achieve this?

Thanks

HandlebarsRuntimeException: Referenced partial name dbimports could not be resolved

Hi Tony,

I'm trying to use your library to customize my scaffolding.
When I try to scaffold the database I get the following exception :

HandlebarsDotNet.HandlebarsRuntimeException: Referenced partial name dbimports could not be resolved
   at HandlebarsDotNet.Compiler.PartialBinder.HandleFailedInvocation(String partialName)
   at lambda_method(Closure , TextWriter , Object )
   at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.<>c__DisplayClass7_0.<Compile>b__0(Object context)
   at EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpScaffoldingGenerator.WriteCode(IModel model, String outputPath, String namespace, String contextName, String connectionString, Boolean useDataAnnotations)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ModelScaffolder.Generate(String connectionString, IEnumerable1 tables, IEnumerable1 schemas, String projectPath, String outputPath, String rootNamespace, String contextName, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Referenced partial name dbimports could not be resolved

My environment :

Windows 10 Enterprise 16299.192 x64
.NET Framework 4.7.1
Visual Studio 2017 Enterprise v15.5.5
.NET Core SDK v2.1.4

Project :

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <AssemblyTitle>EFScaffold API</AssemblyTitle>
    <VersionPrefix>1.1.0</VersionPrefix>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <RuntimeFrameworkVersion>2.0.5</RuntimeFrameworkVersion>
    <OutputType>Library</OutputType>
    <AssemblyName>EFScaffold.API</AssemblyName>
    <PackageId>EFScaffold.API</PackageId>
    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
    <ApplicationIcon>EFScaffold.API.ico</ApplicationIcon>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="EntityFrameworkCore.Scaffolding.Handlebars" Version="1.0.0-beta" />
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.1" PrivateAssets="All" />
    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
    <PackageReference Include="Serilog.Settings.Configuration" Version="2.4.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
    <PackageReference Include="Serilog.Sinks.MSSqlServerCore" Version="1.1.0" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />
  </ItemGroup>

</Project>

Can you help me find out what the problem is ?

Regards, Hakan

Additional code scaffolding question

I am interested if there is a suggested pattern for extending model code generation to produce additional files beyond the DbContext and entities? For example I would like to scaffold repositories. TIA!

Nuget Package Missing

Hi Tony,

Good Morning!

Thanks for your fantastic efforts. You indeed helped developers like us to be more productive and efficient.

I was trying the new scaffolding mechanism this morning, but unfortunately, the nuget file is missing

EntityFrameworkCore.Scaffolding.Handlebars -Pre

Just wanted to let you know.

Thanks.

Update the EF Core 3.0

I'm attempting to use this with EF Core 3.0 Preview 6 and I get this error in the Package Manager Console when I run dotnet ef scaffold. I know you don't advertise compatibility with EF Core 3.0, but I thought I'd file this so you're aware:

  • Visual Studio 2017

  • .NET Core 2.2 class-library project

  • My project references:

      Bricelam.EntityFrameworkCore.Pluralizer        1.0.0  
      EntityFrameworkCore.Scaffolding.Handlebars     2.0.0  
      Microsoft.EntityFrameworkCore                  3.0.0-preview6.19304.10
      Microsoft.EntityFrameworkCore.Design           3.0.0-preview6.19304.10
      Microsoft.EntityFrameworkCore.SqlServer        3.0.0-preview6.19304.10
      Microsoft.EntityFrameworkCore.Tools            3.0.0-preview6.19304.10
    
  • Package Manager Console command:

      PM> dotnet ef dbcontext scaffold "Server=(local);Database=Foobar;Integrated Security=true;" Microsoft.EntityFrameworkCore.SqlServer --project MyProject --data-annotations --context MyDbContext --context-dir Model --force -o Model --verbose
    

Output:

Using project 'MyProject.Data\MyProject.Data.csproj'.
Using startup project 'MyProject.Data\MyProject.Data.csproj'.
Writing 'MyProject.Data\obj\MyProject.Data.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\David\AppData\Local\Temp\tmp84BA.tmp /verbosity:quiet /nologo MyProject.Data\MyProject.Data.csproj
Writing 'MyProject.Data\obj\MyProject.Data.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\David\AppData\Local\Temp\tmp8AC6.tmp /verbosity:quiet /nologo MyProject.Data\MyProject.Data.csproj
dotnet build MyProject.Data\MyProject.Data.csproj /verbosity:quiet /nologo

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.67
dotnet exec --depsfile C:\git\MyProject2\server\MyProject.Data\bin\Debug\netcoreapp2.2\MyProject.Data.deps.json --additionalprobingpath C:\Users\David\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\git\MyProject2\server\MyProject.Data\bin\Debug\netcoreapp2.2\MyProject.Data.runtimeconfig.json C:\Users\David\.dotnet\tools\.store\dotnet-ef\3.0.0-preview6.19304.10\dotnet-ef\3.0.0-preview6.19304.10\tools\netcoreapp3.0\any\tools\netcoreapp2.0\any\ef.dll dbcontext scaffold "Server=(local);Database=MyProject;Integrated Security=true;" Microsoft.EntityFrameworkCore.SqlServer --data-annotations --context MyProjectDbContext --context-dir Model --force -o Model --assembly C:\git\MyProject2\server\MyProject.Data\bin\Debug\netcoreapp2.2\MyProject.Data.dll --startup-assembly C:\git\MyProject2\server\MyProject.Data\bin\Debug\netcoreapp2.2\MyProject.Data.dll --project-dir C:\git\MyProject2\server\MyProject.Data\ --language C# --working-dir C:\git\MyProject2\server --verbose --root-namespace MyProject.Data
Using assembly 'MyProject.Data'.
Using startup assembly 'MyProject.Data'.
Using application base 'C:\git\MyProject2\server\MyProject.Data\bin\Debug\netcoreapp2.2'.
Using working directory 'C:\git\MyProject2\server\MyProject.Data'.
Using root namespace 'MyProject.Data'.
Using project directory 'C:\git\MyProject2\server\MyProject.Data\'.
Finding design-time services for provider 'Microsoft.EntityFrameworkCore.SqlServer'...
Using design-time services from provider 'Microsoft.EntityFrameworkCore.SqlServer'.
Finding design-time services referenced by assembly 'MyProject.Data'.
Using design-time services from assembly 'Bricelam.EntityFrameworkCore.Pluralizer'.
Finding IDesignTimeServices implementations in assembly 'MyProject.Data'...
Using design-time services from class 'ScaffoldingDesignTimeServices'.
System.TypeLoadException: Method 'GenerateModel' in type 'EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator' from assembly 'EntityFrameworkCore.Scaffolding.Handlebars, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b10b51e7b9be6a2e' does not have an implementation.
   at Microsoft.EntityFrameworkCore.Design.ServiceCollectionExtensions.AddHandlebarsScaffolding(IServiceCollection services, ReverseEngineerOptions options, LanguageOptions language)
   at MyProject.Data.ScaffoldingDesignTimeServices.ConfigureDesignTimeServices(IServiceCollection services) in C:\git\MyProject2\server\MyProject.Data\ScaffoldingDesignTimeServices.cs:line 16
   at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.ConfigureUserServices(IServiceCollection services)
   at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.Build(String provider)
   at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable`1 schemas, IEnumerable`1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable`1 schemaFilters, IEnumerable`1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Method 'GenerateModel' in type 'EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator' from assembly 'EntityFrameworkCore.Scaffolding.Handlebars, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b10b51e7b9be6a2e' does not have an implementation.

Could not load file or assembly 'Handlebars, Version=1.9.4.0

In step 5 I receive exception described below. I am using ASP Core 2.1....

System.IO.FileLoadException: Could not load file or assembly 'Handlebars, Version=1.9.4.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661'. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)
File name: 'Handlebars, Version=1.9.4.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661' ---> System.IO.FileLoadException: A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)
at EntityFrameworkCore.Scaffolding.Handlebars.HbsHelperService.RegisterHelpers()
at EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator.GenerateModel(IModel model, String namespace, String contextDir, String contextName, String connectionString, ModelCodeGenerationOptions options)
at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Need version for EF Core 2.2

Hi, I am updating EF Core Power Tools for EF Core 2.2 - are you able to provide a 2.2 version (I have had to disable this for now)

Constructors missing

in advance, sorry about my bad english:

it seems like the constructor code is missing when scaffolding.

the code i'm talking specifically is this one

public SanitariosContext()
        {
        }

        public SanitariosContext(DbContextOptions<SanitariosContext> options)
            : base(options)
        {
        }

(in this example "SanitariosContext" is my dbcontext name)

Property names with special characters (ä,ö,ü) are converted to unicode strings

Hello,

some of the columns in our database contains special characters (ä,ö,ü).
The characters are converted to &#228;, &#246; or &#252; unicode strings.

To solve the issue for me, I have created a hbs-helper, which simple writes the property-name with the WriteSafeString-Method of the TextWriter.

Helper registration:

    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        var options = ReverseEngineerOptions.DbContextAndEntities;
        services.AddHandlebarsScaffolding(options);
        
        Handlebars.RegisterHelper("f-pn", FormatPropertyName);
    }

    void FormatPropertyName(TextWriter writer, object context, object[] args)
    {
        writer.WriteSafeString(args[0].ToString());
    }

Usage in templates:
{{f-pn property-name}}

I think, the property-name template should use the WriteSafeString-Method.

Can rename DbSet Name?

If any possibility to rename DbSet Name of DbContext, example like below

Schema: master
Table : wheater_data
Expected DbsetName : WheateDataList

    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }

    public virtual DbSet<WeatherData> WheateDataList{ get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
        }
    }

Is there any way to turn on suppressConnectionStringWarning option?

I can see that GenerateOnConfiguring takes a very useful looking option: suppressConnectionStringWarning, which prevents a warning (That I'm trying to suppress) from being written.

But, the IServiceCollection.AddHandlebarsScaffolding method that I'm using doesn't appear to take any such option.

Is there another way that I'm missing to get that option turned on?

Many thanks!

ScaffoldingDesignTimeServices not loaded (duplicate of #31)

Running the latest nuget on a new .net core projet.

Running SDK :
PM> dotnet --version
2.1.403

Services class :

`using System;
using System.IO;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.DependencyInjection;

namespace EFCoreScaffold
{
public class ScaffoldingDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
{
// Generate both context and entitites
var options = ReverseEngineerOptions.DbContextAndEntities;

        // Register Handlebars helper
        var myHelper = (helperName: "my-helper", helperFunction: (Action<TextWriter, object, object[]>)MyHbsHelper);

        // Add Handlebars scaffolding templates
        services.AddHandlebarsScaffolding(options);

        // Register Handlebars helper
        services.AddHandlebarsHelpers(myHelper);
    }

    // Sample Handlebars helper
    void MyHbsHelper(TextWriter writer, object context, object[] parameters)
    {
        writer.Write("// My Handlebars Helper");
    }
}

}
`
Class.hbs (Generated by first run of dotnet ef dbcontext scaffold

`{{> imports}}
{{my-helper}}
namespace {{namespace}}
{
{{#if class-annotation}}
{{{class-annotation}}}
{{/if}}

//This is a test !
public partial class {{class}} {{my-helper}}
{
{{{> constructor}}}
{{> properties}}
}
}
`
The comment //This is a test ! , appears, but the helper is not called.

More information for Handlebar Helpers

I have just written Handlebar Helpers in order to place our own naming conventions (we have some special prefixes in DB names for tables and columns I don't want to see in the entities) and for including some converters for properties of a special data type, i.e. we use a DB data type named "Boolean" which is in fact a char(1) containing 'N' for false and 'J' for true (the German Ja/Nein for yes/no).
So I installed a Handlebar Helper for the properties template which detected the [Column(TypeName = "Boolean")] attribute and changed the property's type from string to bool. That worked well so far. But I also have to add code to the context's OnModelCreating method such as entity.HasConversion(GBoolean.Instance). Here I am off because from the "property" Handlebar Helper's method where I detected the attribute and changed the property type I had no access to the helper class that sees the OnModelCreating code.
Because the entities are touched after the DbContext class I could not use global variables to store that info between the calls of the two helper methods.

One way to help here would be to add the entities and properties/attributes info to the entity Handlebars context. This would also help me with including some code to OnModelCreating that places a HasQueryFilter call to every entity containing a field for soft delete.

Couldn't add Helper

Hello

Like I said in EF Core power tools https://github.com/ErikEJ/SqlCeToolbox/issues/697

I have a little issue.. I dont know how add a helper I tried to add in Propreties.hbs the following line before then after the call

Handlebars.registerHelper('ifEquals', function(arg1, arg2, options) {
return (arg1 == arg2) ? options.fn(this) : options.inverse(this);
});
I have issue :

HandlebarsDotNet.HandlebarsRuntimeException: Template references a helper that is not registered. Could not find helper '#ifEquals'

Thank you
Best Regards

Add ability to specify location of CodeTemplates folder

Hi Tony,

I am facing some issue, maybe you can point me to a good place in the code to start debugging:

I am able to invoke the handelbars scaffolder, and drop CodeTemplates, but no replacements takes place after I modify the templates and re-run scaffolding. (I have included the source of both projects for now, until signing gets fixed (if ever))

https://github.com/ErikEJ/SqlCeToolbox/tree/master/src/GUI/POC

https://github.com/ErikEJ/SqlCeToolbox/blob/master/src/GUI/ReverseEngineer20/EFCoreReverseEngineer.cs#L35

"if eq" support in templates

I'm trying to customize the provided templates in order to integrate dcerialize.
It seems to me that I can't test for a simple equality to customize the generated code:

{{spaces 2}}@autoserializeAs(() =>
{{#if (eq property-type "number")}}
Number
{{/if}}
{{#if (eq property-type "string")}}
String
{{/if}}
)

The template does not compile:

HandlebarsDotNet.HandlebarsCompilerException: An unhandled exception occurred while trying to compile the template ---> HandlebarsDotNet.HandlebarsCompilerException: An unhandled exception occurred while trying to compile the template ---> HandlebarsDotNet.HandlebarsCompilerException: An unhandled exception occurred while trying to compile the template ---> System.ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
   at System.Reflection.RuntimeMethodInfo.CreateDelegateInternal(Type delegateType, Object firstArgument, DelegateBindingFlags bindingFlags)
   at HandlebarsDotNet.Compiler.SubExpressionVisitor.GetHelperDelegateFromMethodCallExpression(MethodCallExpression helperCall)
   at HandlebarsDotNet.Compiler.SubExpressionVisitor.VisitSubExpression(SubExpressionExpression subex)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
   at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
   at System.Linq.Expressions.BlockExpression.Accept(ExpressionVisitor visitor)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
   at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
   at System.Linq.Expressions.BlockExpression.Accept(ExpressionVisitor visitor)
   at HandlebarsDotNet.Compiler.FunctionBuilder.Compile(IEnumerable`1 expressions, Expression parentContext, String templatePath)
   --- End of inner exception stack trace ---
   at HandlebarsDotNet.Compiler.FunctionBuilder.Compile(IEnumerable`1 expressions, Expression parentContext, String templatePath)
   at HandlebarsDotNet.Compiler.IteratorBinder.GetDynamicIterator(Expression contextParameter, IteratorExpression iex)
   at HandlebarsDotNet.Compiler.IteratorBinder.VisitIteratorExpression(IteratorExpression iex)
   at System.Linq.Enumerable.SelectIListIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at System.Dynamic.Utils.CollectionExtensions.ToReadOnly[T](IEnumerable`1 enumerable)
   at System.Linq.Expressions.Expression.Block(Type type, IEnumerable`1 variables, IEnumerable`1 expressions)
   at System.Linq.Expressions.BlockExpression.Accept(ExpressionVisitor visitor)
   at HandlebarsDotNet.Compiler.FunctionBuilder.Compile(IEnumerable`1 expressions, Expression parentContext, String templatePath)
   --- End of inner exception stack trace ---
   at HandlebarsDotNet.Compiler.FunctionBuilder.Compile(IEnumerable`1 expressions, Expression parentContext, String templatePath)
   at HandlebarsDotNet.Compiler.FunctionBuilder.Compile(IEnumerable`1 expressions, String templatePath)
   --- End of inner exception stack trace ---
   at HandlebarsDotNet.Compiler.FunctionBuilder.Compile(IEnumerable`1 expressions, String templatePath)
   at HandlebarsDotNet.Handlebars.HandlebarsEnvironment.RegisterTemplate(String templateName, String template)
   at EntityFrameworkCore.Scaffolding.Handlebars.HbsTemplateService.RegisterPartialTemplates()
   at EntityFrameworkCore.Scaffolding.Handlebars.HbsTypeScriptModelGenerator.GenerateModel(IModel model, String namespace, String contextDir, String contextName, String connectionString, ModelCodeGenerationOptions options)
   at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable`1 schemas, IEnumerable`1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable`1 schemaFilters, IEnumerable`1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
An unhandled exception occurred while trying to compile the template

I think I've uderstood that this is because I need to register a helper because the built-in helpers just works for true or false evaluation.

Is there a trick to do that or should we modify the HandleBar.NET Code ?

Entity Name in Plural Form

Hi Tony,

Greetings again.

Is there any way you can help us to create entities without pluralization? We prefer Customer instead of Customers.

DbContext is generated without transformed entity names in OnModelCreating

First of all, thanks for an awesome tool! I have however found a small issue:

Adding an entityNameTransformer to the services transformers applies the transformed name everywhere EXCEPT for the modelBuilder.Entity(...) lines in OnModelCreating.

Fix can be applied in HbsCSharpDbContextGenerator.cs in the InitializeEntityTypeBuilder() function:

private void InitializeEntityTypeBuilder(IEntityType entityType, IndentedStringBuilder sb)
        {
            if (!_entityTypeBuilderInitialized)
            {
                var transformedEntityName = EntityTypeTransformationService.TransformEntityName(entityType.Name);

                sb.AppendLine();
                sb.AppendLine($"modelBuilder.Entity<{transformedEntityName}>({EntityLambdaIdentifier} =>");
                sb.Append("{");
            }

            _entityTypeBuilderInitialized = true;
        }

I am creating a PR for this change. Thanks!

Need strongly signed dll

In order for me to provide this with EF Core Power Tools, as Visual Studio extension, I need a strongly signed assembly - both of this and HandleBars.NET. Are you able to provide that (prefer not to include the source directly)

Add ability to use Handlebars Helper

Include feature like :

  • remove first characters (table name is tblCustomer should be named as class Customer)
  • Fomat string (class name) in CamelCase
    ...
    Such as we can do with Handelbars Helper.

Easier custom renaming of entities and properties

I have written Handlebars helpers for our special naming conventions. It turned out that renaming the navigation properties was pretty hard because I had to split the pregenerated names and repeat the renaming on the individual parts of the name.
A feature for giving two conversion methods would be very handy such as string CreatePropertyName(string) which takes the original field name (e.g "c_first_name") and delivers the desired property name to use in the entity class (e.g. "FirstName"). Likewise a method string CreateEntityClassName(string) that does the naming for entity types.
Maybe an interface with these two methods could be created and this service would be used by Handlebars when it finds this service (also taken into account when generating names for navigation properties).
And: I did the custom renaming of the entity types with my Handlebars helper, but the file name was not affected; how can this be accomplished?

AddHandlebarsHelpers not working

I've been trying to generate comments using helpers but it's not working (unlike comments added in .hbs like //comment). Its almost like if the Helper method is not being called. Also, if there is way to check the property name within i.e.:
if(parameter == "CreatedOn"){
writer.write("//")
}
Using
netcoreapp2.1

**System.NotImplementedException: The method or operation is not implemented.**

I am tring to implment this for .net core 2.2 project. But getting System.NotImplementedException. Any idea?

System.NotImplementedException: The method or operation is not implemented.
at Microsoft.EntityFrameworkCore.Scaffolding.ProviderCodeGenerator.GenerateUseProvider(String connectionString)
at EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpDbContextGenerator.GenerateOnConfiguring(String connectionString, Boolean suppressConnectionStringWarning)
at EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpDbContextGenerator.GenerateClass(IModel model, String contextName, String connectionString, Boolean useDataAnnotations, Boolean suppressConnectionStringWarning)
at EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpDbContextGenerator.WriteCode(IModel model, String namespace, String contextName, String connectionString, Boolean useDataAnnotations, Boolean suppressConnectionStringWarning)
at EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator.GenerateModel(IModel model, String namespace, String contextDir, String contextName, String connectionString, ModelCodeGenerationOptions options)
at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.ScaffoldModel(String connectionString, IEnumerable1 tables, IEnumerable1 schemas, String namespace, String language, String contextDir, String contextName, ModelReverseEngineerOptions modelOptions, ModelCodeGenerationOptions codeOptions)
at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_1.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The method or operation is not implemented.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.