0

Firstly, i apologize for the headline on this one. I'm not really sure how to describe it.

In one of our MVC projects we using AddDbContextPool using our custom context that has a single constructor taking a single parameter of DbContextOptions. All works great when there is a single constructor in the context like this.

However, in order to do a DB migration, it required a empty constructor in the context (as far as i am aware).

If i place this back in the context then my MVC project begins receiving:

The DbContext of type 'DbContext' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions

And if i do not have a empty constructor in the context then i can't generate a new db migration.

So, does anyone know of a way to get this to all play nice with each other? How do i do migrations with a custom context that has a single constructor taking parameter of type DbContextOptions? Or how can i have multiple constructors while keeping my DbContextPooling working?

1 Answer 1

3

However, in order to do a DB migration, it required a empty constructor in the context (as far as i am aware).

That is incorrect. An empty constructor is not required and should not be present. I think a little background on what's happening will help you understand.

EF Core is designed for dependency injection. If expects the DbContextOptions to be provided via dependency injection. However, when running commands from the command-line, your app probably isn't running, and even if it were, there's really no way to somehow remote into its service collection to get the information necessary. As a result, EF Core compensates one of two ways:

  1. If the project the command is being run against is a startup project (it doesn't literally need to be the startup project - just a project that can start), then EF will actually run Program to gain access to that service collection, pulling the DbContext out from there, just as any other normal injection of DbContext would work.

  2. However, if the project is something like a class library, then it can't do this. In that scenario, you can pass it a startup project to use, in addition to the project you're migrating against. If you do this, it works mostly the same as #1 above. Short of that, it needs some other way to know what to do...

Which brings us to that other way. There's an interface called IDesignTimeDbContextFactory. If an implementation of this interface exists in the project EF Core is migrating against, then it will use that to get its context. A typical implementation would look like:

public class MyDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
    public MyDbContext CreateDbContext(string[] args)
    {
        var options = new DbContextOptionsBuilder<MyDbContext>()
            .UseSqlServer("[connection string here]")
            .Options;

        return new MyDbContext(options);
    }
}

Aside

The connection string should be hard-coded for the most part. People tend to get a little crazy here and try to set up a whole parallel configuration setup, and it's largely unnecessary. As the name of the interface indicates, this is for development. This implementation is not something that should ever be running in any other environment, so there's no reason to have environment-specific settings. Additionally, a development connection string can usually be constructed in a developer-inspecific way, so it's usually not necessary to change from one developer to the next. If you do need that, then simply load in the User Secrets config provider to allow individual developers to define their personal connection strings from there.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.