Scaffold EF Core entities with interface

Viewed 3115

I am using Entity Framework Core tools to create Entities and DBContext from the existing database.

Scaffold-DbContext "Server=XXXXXX;Database=MyDB;User ID=xxxx;Password=xxxxxxx" Microsoft.EntityFrameworkCore.SqlServer -ContextDir .-OutputDir Entities -Force

This working. But is there any way to scaffold all the entities with known interface? So i have interface IEntityBase and i want all the entities to have this interface

Note This question is specific to EF Core 2+ and scaffolding

Update 1
So as per the SO Suggesion i have created CSharpEntityTypeGenerator and IDesignTimeServices The accepted answer is not valid for EF Core > 2.* so i am using the suggession from @Chris Peacock

public class MyEntityTypeGenerator: CSharpEntityTypeGenerator
{
    public MyEntityTypeGenerator(ICSharpHelper cSharpHelper)
        : base(cSharpHelper)
    {
    }

    public override string WriteCode(IEntityType entityType, string @namespace, bool useDataAnnotations)
    {
        string code = base.WriteCode(entityType, @namespace, useDataAnnotations);

        var oldString = "public partial class " + entityType.Name;
        var newString = "public partial class " + entityType.Name + " : EntityBase";

        return code.Replace(oldString, newString);
    }
}


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

There is one change i had to make. CSharpEntityTypeGenerator constructor takes ICSharpHelper as parameter instead of ICSharpUtilities

These two classes are in Data assembly which is not a startup project.

At package manager console i executed the scaffolding command again. However i do not see generated entities have base class.

How scaffolding framework would know to use my custom generator? I am adding generator in serviceCollection but looks like the code never get executed

Am i missing something?

2 Answers

I think these options should have been provided as as a part of EF Scaffolding tool by default.

But here is my code. I am using Microsoft.EntityFrameworkCore.Design 2.2.4 and Microsoft.EntityFrameworkCore.SqlServer 2.2.4 and based on my experience with .NET Core this may change in future version

CSharpEntityTypeGenerator

public class MyEntityTypeGenerator: CSharpEntityTypeGenerator
{
    public MyEntityTypeGenerator(ICSharpHelper cSharpUtilities)
        : base(cSharpUtilities)
    {
    }

    public override string WriteCode(IEntityType entityType, string @namespace, bool useDataAnnotations)
    {
        Console.WriteLine(entityType.Name);

        string code = base.WriteCode(entityType, @namespace, useDataAnnotations);

        var oldString = "public partial class " + entityType.Name;
        var newString = "public partial class " + entityType.Name + " : EntityBase";

        return code.Replace(oldString, newString);
    }
}

By default scaffolding generates classes with the same name as Table name. In our case the table names are Pluralize, but we want class name Singularize. So you have to implement Microsoft.EntityFrameworkCore.Design.IPluralizer. I used Inflator utility. However, note that i could not add Inflector using Nuget in .Net Core project. Looks like it does not support .NET Core yet. So i have added the single code file instead in my project.

IPluralizer

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

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

IDesignTimeServices
You need to add this class in startup project. Initially, i had this class in the same project as other classes but that did not work. I moved this class in startup project, (In my case that is ASP.NET Core project) and it worked

public class MyDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
    {
        // Start debugger
        System.Diagnostics.Debugger.Launch();
        serviceCollection.AddSingleton<ICSharpEntityTypeGenerator, MyEntityTypeGenerator>();
        serviceCollection.AddSingleton<IPluralizer, MyPluralizer>();
    }
}
Related