Custom scaffolding logic for database first Entity Framework Core

asp.net-core c# entity-framework-core

Question

I'm new to Entity Framework Core as I'm currently migrating over from EF6. We use a database first model.

I've created a .Net Standard class library where I've imported EF Core and have used the scaffolding command in VS to import one of my tables as a test - which worked.

We have a couple of different replica databases that we use for geo-redundancy and reporting purposed, but all have the same model.

I've set up the different connection options, somewhat like point 2 in the answer in this post Using Entity Framework Core migrations for class library project so we can support connections to the different databases.

Now I want to go about adding the rest of the tables in. I have seen mention of Migrations, but that seems to be for code first models.

I then tried to use the "-Force" command on the scaffolding, which did import an additional table, but I lost my multi-database support.

In EF6 I had this logic in the Context.tt file, so when I retrieved updates from the database it would retain the custom connection options I had.

Is there a way to replicate this in EF Core or something I am missing?

Also, for something as simple as a new column on a table, should I still run the same command?

Thanks in advance,

David

* UPDATED *

I ended up using EF Core Power Tools which is a great package and allows complete control over the model, much like the context.tt file used to.

For anyone looking in future, I reverse engineered and used the Handlebars templates in EF Core Power Tools. I pass the 3 connection strings I use in the startup of the application and can then set optional booleans to indicate which connection to use - an enum may be more elegant for anyone starting again but this makes migration easier for us. In the DbConstructor.hbs, I updated it to:

{{spaces 8}}public {{class}}(bool ReadOnlyDatabase = false, bool ReportsDatabase = false) : base()
{{spaces 8}}{ 
            if (ReadOnlyDatabase)
                _connectionString = ReadOnlyContext;
            else if (ReportsDatabase)
                _connectionString = ReportsContext;
            else
                _connectionString = ReadWriteContext;
{{spaces 7}} }

The DbContext.hbs file is:

{{> dbimports}}

namespace {{namespace}}
{
    public partial class {{class}} : DbContext
    {
        public static string ReadWriteContext = "";
        public static string ReadOnlyContext = "";
        public static string ReportsContext = "";

        private readonly string _connectionString;
{{{> dbsets}}}
{{#if entity-type-errors}}
{{#each entity-type-errors}}
{{spaces 8}}{{{entity-type-error}}}
{{/each}}

{{/if}}

{{{> dbconstructor}}}

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(_connectionString);
        }
{{{on-model-creating}}}
    }
}
1
0
5/10/2019 9:57:57 AM

Accepted Answer

Supply a DbContextOptions to the constructor:

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

Maybe EF Core Power Tools can help you? (I am the author)

1
5/9/2019 5:46:23 PM

Popular Answer

You need to post more of your code so we can see what’s going on. At a guess it sounds like you are customizing the generated context class. It will be overwritten with each scaffold operation and as you note the migration support is there to drive db Schema updates from model changes. I.e. it’s for code first.

The db first scaffold approach seems that to be written with the expectation that the scaffold will be done once and thereafter models and contexts will be manually updated. We have a workflow that involves re scaffolding the DbContext in response to db schema updates and consequently do three things:

  • scaffold a localhost or SSPI db so the embedded connection string contains no passwords of value.
  • tolerate the annoying warning in CI/CD about the connection string the scaffolder generates each time that cant be disabled.
  • we use extension methods to add functionality to the DbContext when necessary so we never need to alter the generated code.

Now I would not suggest extension methods to initialize the different connection strings.

Those I am sure are already coming from config but if not, and you are making a console rather than asp.net core app which makes configuration driven creation of DbContexts really easy I would really suggest learning how to use at least Microsoft.Extensions.Configuration to configure your DbContext instances from an appSettings.

I can’t share a code sample of initializing a DBContext with an DbOptionsBuilder directly because my guilty secret is I always get the DI in Asp.net Core to do it for me.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow