Using EF6 with .NET Core

Home / Using EF6 with .NET Core

EntityFramework 7 is the defacto ORM used with .NET Core to provide cross-platform compatible data access. EF7 is missing many features that are present in EF6, though. My initial apprehension was that this would create a scenario where one could not use .NET Core if their projects relied on EF6 features. Fortunately, it’s pretty easy to get EF6 working with .NET Core. The sacrifice is a loss of cross-platform hosting ability.


Starting from scratch, we must create our web project such that it targets ASP.NET Core w/ .NET Framework.

You’ll see in the project dependencies that the .NET 4.6.1 reference is provided.

Follow the newer conventions, we add our connection string to the appsettings.json file:

{
  "ConnectionStrings": {
    "DefaultConnection": "server=127.0.01;database=default;Integrated Security=True;"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

I create a seperate project for my DataAccess layer with a context inheriting from my own utility’s BaseContext. The constructor simply takes a connection string. The part that is missing to get things working is that, since EF6 relies on loading configuration information from *.config files, the client type is no longer available. We have to provide this information to EF by implementing a DbConfiguration attribute. I put this attribute class into the same file w/ my context and decorated the context with the attribute.

public class DbConfig : DbConfiguration
{
    public DbConfig()
    {
        SetProviderServices("System.Data.SqlClient", SqlProviderServices.Instance);
    }
}


[DbConfigurationType(typeof(DbConfig))]
public class MyContext : BaseContext
{
    public MyContext(string connectionStringName)
        : base(connectionStringName)
    {

    }
}

If we want to use .NET Core’s new dependency injection engine, we need to inject our context and whatever else we’re interested in. My repositories have constructors that utilize the context and are all derived from a base implementation. I have a simple routine that injects the context and all repositories.

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Add DbContext
    services.AddScoped(provider =>
    {
        var connectionString = Configuration.GetConnectionString("DefaultConnection");
        return new MyContext(connectionString);
    });

    // Repositories
    var assembly = Assembly.GetAssembly(typeof(MyContext));
    var types = assembly
        .GetTypes()
        .Where(x => x.IsClass && x.BaseType != null && x.BaseType.IsGenericType && x.BaseType.GetGenericTypeDefinition() == typeof(BaseRepository<>))
        .ToList();

    foreach (var type in types)
    {
        var interfaceType = type.GetInterfaces().FirstOrDefault();
        services.AddTransient(interfaceType, type);
    }

    // Add framework services.
    services.AddMvc();
}

I have looked at using migrations, since I’m using Database-first modeling, but I presume it would require a bit of set-up as well due to the way the migrate.exe finds connection strings. In the best case, migrate.exe could be run directly with a connection string passed-in to avoid configuration headaches.

Finally, in the default HomeController, I am injecting an IRepository>T< to confirm querying the database works – and it does!

public class HomeController : Controller
{
    private IRepository<SomeOject> _objRepo;

    public HomeController(IRepository<SomeOject> objectRepository)
    {
        _objRepo = objectRepository;
    }

    public IActionResult Index()
    {
        var objects = _objRepo.Get(x => true).Take(10).ToList();
        return View();
    }
}

Leave a Reply