Open Closed

ReplaceDbContext with MultiTenant #3892


User avatar
0
cala created

Hi,

when joining on identityuser in our modules services, we get an "Cannot use multiple context instances within a single query execution" exception. Our DbContextBase has the ReplaceDbContext attribute and implements all dbcontext interfaces of these dbcontext

  • ABP Framework version: v5.3.0
  • UI type: Blazor
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no
  • Exception message and stack trace:
System.InvalidOperationException: Cannot use multiple context instances within a single query execution. Ensure the query uses a single context instance.
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.ExtractParameters(Expression expression, Boolean clearEvaluatedValues)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.ExtractParameters(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExtractParameters(Expression query, IParameterValues parameterValues, IDiagnosticsLogger`1 logger, Boolean parameterize, Boolean generateContextAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at Volo.Abp.EntityFrameworkCore.EfCoreAsyncQueryableProvider.CountAsync[T](IQueryable`1 queryable, CancellationToken cancellationToken)
   at Volo.Abp.Linq.AsyncQueryableExecuter.CountAsync[T](IQueryable`1 queryable, CancellationToken cancellationToken)
   at ***.DMSAlarmService.GetListAsync(PagedAndSortedResultRequestDto input) in ***\DMSAlarmService.cs:line 37
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
   at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at ***.AcknowledgeList.LoadAlarmHistory() in ***\AcknowledgeList.razor:line 47
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

Context:

Is there some confgiruation we missed ? used this approach in different project ( without Multi Tenant ) and had no problems


11 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Please try to use code

    context.Services.AddAbpDbContext<YourDbContext>(options =>
    {
        options.ReplaceDbContext<IIdentityDbContext>();
    });
    
  • User Avatar
    0
    cala created

    nope - doesnt work. Always the same exception tried:

    • ReplaceDbContext inside AddAbpDbContext ( only IIdentityDbContext ) and attribute on context
    • ReplaceDbContext inside AddAbpDbContext ( only IIdentityDbContext ) without attribute on context
    • ReplaceDbContext inside AddAbpDbContext ( all replaced context ) and attribute on context
    • ReplaceDbContext inside AddAbpDbContext ( all replaced context ) without attribute on context
    • ( also tried to put options.AddDefaultRepositories( includeAllEntities: true ) in PreConfigureServices )

    So you say you tried and it works for you ?

  • User Avatar
    0
    cala created

    updated to 6.0.0 -> same result

    here is an example project, tried to be as close as possible to our project / structure. ( removed test projects, removed apb commercial from nuget config )

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    What are steps to reproduce the problem?

  • User Avatar
    0
    cala created
    1. start provided project
    2. klick on ExampleView in menu
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    var query = from example in await Repository.GetQueryableAsync()
    	join user in await _userRepository.GetQueryableAsync() on example.UserId equals user.Id
    	select new
    	{
    		example,
    		user.Name
    	};
    

    The Repository is MultiTenantDbReplace.Example.EntityFrameworkCore.ExampleDbContext The _userRepository is MultiTenantDbReplace.EntityFrameworkCore.MultiTenantDbReplaceTenantDbContext

  • User Avatar
    0
    cala created

    im not sure what you mean.

    So how do i get both entities in the same context ? I thought that is the purpose of ReplaceDbContext ( tried to add IMultiTenant to exampleEntity, but same result )

  • User Avatar
    0
    cala created

    Found one problem: options.AddDefaultRepository<TEntity> prevents ReplaceDbContext to work But ExampleEntity still in host context and user in tenant context

  • User Avatar
    1
    cala created

    Found the last problem: you need a custom repository, it looks like MultiTenant doesnt work with default genrated repository

    With custom repository and multi-tenant, all entities are on the same context, finally.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    👍👍👍

  • User Avatar
    0
    cala created

    i belive there are two bugs that should be fixed:

    1. AddDefaultRepository on an entity which is part of an context with ReplaceDbContext prevents this entity from being part of the target context
    2. injected default repositories like IReadOnlyRepository in application services for entities with IMultiTenant get the host context instead of the tenant context when they do not have a custom repository
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11