Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Core Customize Scaffolding

I have done scaffolding of my SQLServer database. And it creates the POCO objects in the specified folder. What i would like to do is that it extends from my base class. I also use repository pattern so i need to have Id key on every entity and I don't want to change that each time i rescaffold the database.

Scaffold Model Example

public partial class Food
{
     public int Id { get; set; }
     public string Name { get; set; }
     public string Description { get; set; }
     public double Price { get; set; }
}

Expected Result:

public partial class Food : EntityBase
{
     public string Name { get; set; }
     public string Description { get; set; }
     public double Price { get; set; }
}

public class EntityBase : IEntityBase
{
    public int Id { get; set; }
}
like image 780
Dživo Jelić Avatar asked Nov 21 '16 19:11

Dživo Jelić


People also ask

What is scaffolding in Entity Framework Core?

Scaffolding a database produces an Entity Framework model from an existing database. The resulting entities are created and mapped to the tables in the specified database. For an overview of the requirements to use EF Core with MySQL, see Table 7.2, “Connector/NET Versions and Entity Framework Core Support”).

What is Scaffold-DbContext command?

The above Scaffold-DbContext command creates entity classes for each table in the SchoolDB database and context class (by deriving DbContext ) with Fluent API configurations for all the entities in the Models folder. The following is the generated Student entity class for the Student table.

Is Scaffold-DbContext command is used in EF Code First approach?

Entity Framework Core supports Database-First approach via the Scaffold-DbContext command of Package Manager Console. This command scaffolds a DbContext and entity type classes for a specified database.


2 Answers

You can use DbContextWriter & EntityTypeWriter to customize scaffold output.

In newer versions of entity core writers renamed:

  • DBContextWriter ==>> CSharpDbContextGenerator
  • EntityTypeWriter ==>> CSharpEntityTypeGenerator

Write some custom type writer, you can override everything and you will get your own code generator:

//HERE YOU CAN CHANGE THE WAY TYPES ARE GENERATED AND YOU CAN ADD INTERFACE OR BASE CLASS AS PARENT.
public class CustomEntitiyTypeWriter : EntityTypeWriter
{
    public CustomEntitiyTypeWriter([NotNull] CSharpUtilities cSharpUtilities)
        : base(cSharpUtilities)
    { }

    // Write Code returns generated code for class and you can raplec it with your base class
    public override string WriteCode([NotNull] EntityConfiguration entityConfiguration)
    {
        var classStr = base.WriteCode(entityConfiguration);

        var defaultStr = "public partial class " + entityConfiguration.EntityType.Name;
        var baseStr = "public partial class " + entityConfiguration.EntityType.Name + " : EntityBase";

        classStr = classStr.Replace(defaultStr, baseStr);

        return classStr;
    }      
}

declare it in setup:

public static void ConfigureDesignTimeServices(IServiceCollection services)
           => services.AddSingleton<EntityTypeWriter, CustomEntitiyTypeWriter>();

and then scaffold db, you can do the same for DBContext with CustomDBContextWriter.

like image 200
Tornike Choladze Avatar answered Oct 13 '22 23:10

Tornike Choladze


In case you want to modify entity names (and file and class names) here's something that might help:

Based on Chris Peacock's answer (and comments) you can build two classes to modify the names of entities and files (this works in Core 2.2).

public class CustomEFUtilities : CSharpUtilities
{
    public override string Uniquifier(
        string proposedIdentifier, ICollection<string> existingIdentifiers)
    {
        var finalIdentifier = base.Uniquifier(proposedIdentifier, existingIdentifiers);
        
        // your changes here
        if (finalIdentifier.StartsWith("tl"))
        {
            finalIdentifier = finalIdentifier.Substring(2);
        }
        
        return finalIdentifier;
    }
}

And similarly:

public class CustomEFDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
    {
        serviceCollection.AddSingleton<ICSharpUtilities, CustomEFUtilities>();
    }
}

Edit (EF Core 3.1)

A breaking change was introduced (https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#microsoftentityframeworkcoredesign-is-now-a-developmentdependency-package) so you need to modify your project file:

If you need to reference this package to override EF Core's design-time behavior, then you can update PackageReference item metadata in your project.

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
  <PrivateAssets>all</PrivateAssets>
  <!-- Remove IncludeAssets to allow compiling against the assembly -->
  <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>
like image 35
DavidC Avatar answered Oct 14 '22 00:10

DavidC