Mr. Spock
Mr. Spock

Reputation: 355

DbContextOptionsBuilder<someType> does not contain a definition for UseSqlServer()

I have looked at several similar questions here but nothing has helped so far.

I am trying to dynamically create a DbContext based on a type that isn't known until runtime. The DbContext is in another library that I reference in my app. I need to pass a DbContextOptions object to the DbContext's constructor. SO I am creating a DbContextOptionsBuilder and trying to call the UseSqlServer() method passing in a connection string. However I get the error in the title.

Other similar questions always say to add the packages Microsoft.EntityFrameworkCore and Microsoft.EntityFrameworkCore.SqlServer and I have done that but without success.

Here is my code right now:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.SqlServer;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

private DbContext GetDbContext()
{
    Console.WriteLine("\nGetting DB Context...");

    Assembly LaytonDBSets = Assembly.Load("LaytonDBSets.Core");

    List<TypeInfo> dbContexts = LaytonDBSets.DefinedTypes.Where(t => typeof(DbContext).IsAssignableFrom(t)).ToList();

    foreach (TypeInfo ti in dbContexts)
    {
        Type ctxType = LaytonDBSets.GetType(ti.FullName);

        // Get the DbContextOptions to pass to the DbContext constructor
        Type dbContextOptionsBuilderBase = typeof(DbContextOptionsBuilder<>);
        Type dbContextOptionsBuilderType = dbContextOptionsBuilderBase.MakeGenericType(ctxType);
        dynamic dbContextOptionsBuilder = Activator.CreateInstance(dbContextOptionsBuilderType);
        string connStr = iconfig.GetConnectionString(ti.Name);
        dbContextOptionsBuilder.UseSqlServer(connStr); // ERROR HERE
        var options = dbContextOptionsBuilder.Options;

        dynamic ctx = Activator.CreateInstance(ctxType, args: new object[] { options });

        // stuff to be added...
    }

    // stuff to be added...
}

If there is a batter way to do what I am attempting please let me know, I have never done anything like this before.

Upvotes: 0

Views: 593

Answers (1)

Svyatoslav Danyliv
Svyatoslav Danyliv

Reputation: 27481

This is the helper class to do that:

public class ContextHelper
{
    public static DbContext CreateDbContext<T>(string connectionString) where T : DbContext
    {
        var optionsBuilder = new DbContextOptionsBuilder<T>();
        optionsBuilder.UseSqlServer(connectionString);

        var options = optionsBuilder.Options;
        var context = (DbContext)Activator.CreateInstance(typeof(T), options);

        return context;
    }

    private static MethodInfo _createDbContext = typeof(ContextHelper).GetMethod("CreateDbContext", new Type[]{typeof(string)});

    public static List<DbContext> CreateDbContexts(IEnumerable<(Type Type, string ConnectionString)> contextTypes)
    {
        var result = new List<DbContext>();
        foreach (var contextType in contextTypes)
        {
            result.Add((DbContext)_createDbContext.MakeGenericMethod(contextType.Type)
                .Invoke(null, new[] {contextType.ConnectionString}));
        }

        return result;
    }
}

Usage in your case:

var typeWithConnectionString = 
    dbContexts.Select(ti => (LaytonDBSets.GetType(ti.FullName), iconfig.GetConnectionString(ti.Name)));

var contexts = ContextHelper.CreateDbContexts(typeWithConnectionString);

Upvotes: 2

Related Questions