Skip to content

Multiple EF contexts #269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
joshhubers opened this issue Apr 23, 2018 · 1 comment
Closed

Multiple EF contexts #269

joshhubers opened this issue Apr 23, 2018 · 1 comment

Comments

@joshhubers
Copy link
Contributor

joshhubers commented Apr 23, 2018

First off, thanks for the fantastic library. It has been extremely beneficial for my project.

Is it possible to use multiple EF Core DbContexts? I'm attempting to add two different contexts, but the second overrides the first.

Ex.

services.AddJsonApi<ContextA>(opt =>
        {
            opt.AllowCustomQueryParameters = true;
            opt.Namespace = "api/v1";
        }, mvcBuilder);

services.AddJsonApi<ContextB>(opt =>
        {
            opt.AllowCustomQueryParameters = true;
            opt.Namespace = "api/v1";
        }, mvcBuilder);

Where both ContextA and ContextB are EF Core DbContext's.

When I request resources from controllers that use ContextB, I get the resources as expected. When I request from controllers that use ContextA I get a
"ArgumentException","detail":"DbSet of type {DbSet of ContextA} not found on the DbContext"

Commenting out the first AddJsonApi call changes the which context is working as expected.

@jaredcnance
Copy link
Contributor

jaredcnance commented Apr 23, 2018

Hi - yes! I am currently working on an application that has this requirement. I haven't finished validating this, but it looks something like:

services.AddJsonApi(options => {
  options.BuildContextGraph((builder) =>
  {
     // add both contexts using the builder
     builder.AddDbContext<DbContextA>();
     builder.AddDbContext<DbContextB>();
  });
}, mvcBuilder);

Create an implementation of IDbContextResolver for each context:

 public class DbContextAResolver : IDbContextResolver
    {
        private readonly DbContextA _context;

        public DbContextAResolver(DbContextA context)
        {
            _context = context;
        }

        public DbContext GetContext() => _context;

        public DbSet<TEntity> GetDbSet<TEntity>() where TEntity : class
            => _context.GetDbSet<TEntity>();
    }

Register new IDbContextResolver implementations:

services.AddScoped<DbContextAResolver>();
services.AddScoped<DbContextBResolver>();

You can then create a general repository for each context and the inject it per resource type. This example shows how you can create a single DbContextARepository for all entities that are members of DbContextA.

public class DbContextARepository<TEntity> 
: DefaultEntityRepository<TEntity> where TEntity : class, IIdentifiable<int>
    {
        public DbContextARepository(
            ILoggerFactory loggerFactory,
            IJsonApiContext jsonApiContext,
            DbContextAResolver contextResolver)
        : base(loggerFactory, jsonApiContext, contextResolver)
        { }
    }

Then inject the repository for the correct entity, in this case Foo is a member of DbContextA:

services.AddScoped<IEntityRepository<Foo>, DbContextARepository<Foo>>();

I recognize that this is not ideal, and I plan on fully documenting this process once I've had some time to flush out any possible challenges. Also, this should be included as part of #241 to improve the DX around the use of multiple contexts. Ideally, we'd like to be able to provide this functionality without this amount of boilerplate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants