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)
-
0
Can you try using IDbContextProvider<TDbContext> instead of Repository for join queries?
example:
dbContextProvider.GetDbContext().Set<YourEntity>()....
-
0
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.
-
0
Hi, Some update about this topic?
Thank you.
-
0
@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.
-
0
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.
-
0
@ismcagda Do you have some thoughts about this?
-
0
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 ofAbpDbContext
as workaround.You might also need to enable query filter in
QueryContext
similar toAbpDbContext
see https://github.com/aspnetboilerplate/aspnetboilerplate/blob/c64804aa17eecb0078d18dd79997eadb6d041113/src/Abp.EntityFrameworkCore/EntityFrameworkCore/AbpDbContext.cs#L114-L119
-
0
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.
-
0
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.