Assign Tenant.AgnosticTenantId in populator (#7252)

* Assign Tenant.AgnosticTenantId in populator

* Corrected comment

* Fix entities persisted with NULL TenantId instead of default tenant

Use normalized TenantId property (which returns empty string for default tenant) instead of Tenant?.Id (which returns null when no tenant is set).

When Tenant?.Id returned null: TenantAwareDbContextFactory set dbContext.TenantId to null, ApplyTenantId skipped assigning TenantId, entities were saved with NULL TenantId, and query filters using SQL equality against NULL never matched these entities.

This affected all EF Core stores including BookmarkStore and any store using bulk upsert operations.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Update src/modules/Elsa.Workflows.Runtime/Services/DefaultWorkflowDefinitionStorePopulator.cs

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* PR comments

* Set Tenant.AgnosticTenantId when no tenantId is specified

---------

Co-authored-by: Ralf <Ralf@Careconnections.nl>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
RalfvandenBurg 2026-02-09 11:03:49 +01:00 committed by GitHub
parent 34ecf02c32
commit 09d768791a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 9 additions and 8 deletions

View file

@ -182,7 +182,7 @@ public class Store<TDbContext, TEntity>(IDbContextFactory<TDbContext> dbContextF
}
// When doing a custom SQL query (Bulk Upsert), none of the installed query filters will be applied. Hence, we are assigning the current tenant ID explicitly.
var tenantId = serviceProvider.GetRequiredService<ITenantAccessor>().Tenant?.Id;
var tenantId = serviceProvider.GetRequiredService<ITenantAccessor>().TenantId;
foreach (var entity in entityList)
{
if (entity is Entity entityWithTenant)

View file

@ -32,6 +32,6 @@ public class TenantAwareDbContextFactory<TDbContext>(
private void SetTenantId(TDbContext context)
{
if (context is ElsaDbContextBase elsaContext)
elsaContext.TenantId = tenantAccessor.Tenant?.Id;
elsaContext.TenantId = tenantAccessor.TenantId;
}
}

View file

@ -1,3 +1,4 @@
using Elsa.Common.Multitenancy;
using Elsa.Workflows.Management.Materializers;
using Elsa.Workflows.Runtime.Features;
using Elsa.Workflows.Runtime.Options;
@ -10,7 +11,7 @@ namespace Elsa.Workflows.Runtime.Providers;
/// Provides workflows to the system that are registered with <see cref="WorkflowRuntimeFeature"/>
/// </summary>
[UsedImplicitly]
public class ClrWorkflowsProvider(
public class (
IOptions<RuntimeOptions> options,
IWorkflowBuilderFactory workflowBuilderFactory,
IServiceProvider serviceProvider) : IWorkflowsProvider
@ -41,7 +42,7 @@ public class ClrWorkflowsProvider(
{
Id = id,
DefinitionId = definitionId,
TenantId = workflow.Identity.TenantId
TenantId = workflow.Identity.TenantId ?? Tenant.AgnosticTenantId
};
var materializerContext = new ClrWorkflowMaterializerContext(workflowBuilder.GetType());

View file

@ -60,7 +60,7 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
{
var providers = _workflowDefinitionProviders();
var workflowDefinitions = new List<WorkflowDefinition>();
var currentTenantId = (_tenantAccessor.Tenant?.Id).NormalizeTenantId();
var currentTenantId = _tenantAccessor.TenantId;
foreach (var provider in providers)
{
@ -69,7 +69,7 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
foreach (var result in results)
{
// Normalize tenant IDs for comparison (null becomes empty string)
var definitionTenantId = result.Workflow.Identity.TenantId.NormalizeTenantId();
var definitionTenantId = result.Workflow.Identity.TenantId ?? _tenantAccessor.TenantId;
// Only import workflows belonging to the current tenant or tenant-agnostic workflows (TenantId = "*").
if (definitionTenantId != currentTenantId && definitionTenantId != Tenant.AgnosticTenantId)
@ -191,8 +191,8 @@ public class DefaultWorkflowDefinitionStorePopulator : IWorkflowDefinitionStoreP
await UpdateIsPublished();
// Determine the tenant ID for the workflow definition
// If the workflow has no tenant ID, use the current tenant (normalized to handle null -> "")
var workflowTenantId = workflow.Identity.TenantId ?? (_tenantAccessor.Tenant?.Id).NormalizeTenantId();
// If the workflow has no tenant ID, use the current tenant (normalized to handle null -> "*")
var workflowTenantId = workflow.Identity.TenantId ?? _tenantAccessor.TenantId;
var workflowDefinition = existingDefinitionVersion ?? new WorkflowDefinition
{