Base solution for your next web application
Open Closed

Registration problem of IRepository with MultiDbContext and joins #6896


User avatar
0
ivanosw1 created

Hi, we would like to share an issue when you have multiple dbcontext and you want to join tables owned by two different context. Is not simple to explain so we have done a poc to better understand.

Scenario: Multiple DB Context referencing same table

ContextA
DbSet<MyTableA>
DbSet<MyTableB>

ContextB
DbSet<MyTableC>
DbSet<MyTableA>

In ContextB 
	IRepository<MyTableC> TableC
	IRepository<MyTableA> MyTableA

	Join TableC on TableA  <- Error Null reference for TableA because in registered only in ContextA 

Problem The table is registered only on the first context discovered and when an other context requires access to the same table, his context is missing the table. You can't join table owned by two different contexts, also if you registrer the dbset in both of them.

Desired behaviour Register the dbset in both context

Workaround Register a DbSet using an empty class that extends the firts DbSet.

You can find the code to download here

Thank you


9 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    Can you try using IDbContextProvider<TDbContext> instead of Repository for join queries?

    example:

    dbContextProvider.GetDbContext().Set<YourEntity>()....
    
  • User Avatar
    0
    ivanosw1 created

    Hi @maliming sorry I didn't report the link to the previous thread

    What you say is what we are doing now and you said that is a valid solution, but is a workaround and we are loosing the IRepository behaviours. Every "deviation" to the standard path/architecture can cause problems in the future if the implementaion changes, and as our project is very big, we dont' want to take the wrong way. How would you solve the problem?

    There is a flipside with this workaround? Is compatible with what have you planned for the next releases ? This is our main fear.

    Thank you.

  • User Avatar
    0
    ivanosw1 created

    Hi, Some update about this topic?

    Thank you.

  • User Avatar
    0
    ismcagdas created
    Support Team

    @ivanosw1 sorry for our late response. Do you believe that this is related to AspNet Zero ? It seems like an EF Core problem to me. As far as I know, you can't join two tables from two different dbContexes.

  • User Avatar
    0
    ivanosw1 created

    Yes @ismcagdas you are right. Due to the fact that is not possible join two different context, we have created a new QueryContext that has the responsability to make all cross context queries. The use of dbContextProvider.GetDbContext().Set<YourEntity>().... is suitable for our requirements, but the side effect is that another context fails to retrive the correct IRepository because is registered twice.

    What we think that could resolve the issue is the possibility to NOT register the IRepository for all the dbsets on the QueryContext but only for the all other contexts (For example with an attribute in the context that skips the registration). This solution could also resolve the huge problem of very slow startup when you need to resolve many respository in ctor.

  • User Avatar
    0
    ivanosw1 created

    @ismcagda Do you have some thoughts about this?

  • User Avatar
    0
    ryancyq created
    Support Team

    Hi @ivanosw1, does your QueryContext require any database write operation?

    if it does not, you can try to change your QueryContext to inherit from DbContext instead of AbpDbContext as workaround.

    You might also need to enable query filter in QueryContext similar to AbpDbContext

    see https://github.com/aspnetboilerplate/aspnetboilerplate/blob/c64804aa17eecb0078d18dd79997eadb6d041113/src/Abp.EntityFrameworkCore/EntityFrameworkCore/AbpDbContext.cs#L114-L119

  • User Avatar
    0
    ivanosw1 created

    Hi @ryancyq and @ismcagdas We have investigated more deeply in source code and probably found a solution thas is also an ANZ standard. Please tell me what do you think about.

    • Use for every crud operations your contexts as usual (: AbpContext and IRepository).
    • For the context used only for for queries, use :AbpContext but with a different AutoRepositoryType

    [AutoRepositoryTypesAttribute(typeof(INullRepo<>), typeof(INullRepoKey<,>), typeof(NullRepo<>), typeof(NullRepoKey<,>), WithDefaultRepositoryInterfaces = false)]

    INullRepo, INullRepoKey don't do nothing so the IRepository is not registered twice and at runtime is used the only one configured in the owner repository (so only one class and one configuration)

    Our tests look good but I would like to hear some thoughts from your team. Thank you.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @ivanosw1

    Sorry for my late reply, this is a good solution. You can also try to create mirror entities (like MyTableA and MyTableA1) which are exactly same and add MyTableA to ContextA and MyTableA1 to ContextB. In that way, you might not have to create INullRepo.