// 1. Domain entity
public class Project : BaseEntity, ITenantScopedEntity, IAuditableEntity
{
public string Name { get; private set; } = string.Empty;
public string Description { get; private set; } = string.Empty;
public Guid TenantId { get; private set; } // required by ITenantScopedEntity
public Tenant Tenant { get; private set; } = null!;
public DateTime CreatedAt { get; set; } // required by IAuditableEntity
public DateTime? UpdatedAt { get; set; }
private Project() { }
public static Project Create(string name, string description, Guid tenantId)
{
return new Project
{
Id = Guid.NewGuid(),
Name = name,
Description = description,
TenantId = tenantId
};
}
}
// 2. EF Core configuration — include the global query filter
public class ProjectConfiguration : IEntityTypeConfiguration<Project>
{
private readonly TenantContext _tenantContext;
public ProjectConfiguration(TenantContext tenantContext)
{
_tenantContext = tenantContext;
}
public void Configure(EntityTypeBuilder<Project> builder)
{
builder.ToTable("projects");
builder.HasKey(p => p.Id);
builder.Property(p => p.Name).HasMaxLength(200).IsRequired();
builder.Property(p => p.Description).HasMaxLength(2000);
builder.HasIndex(p => p.TenantId);
// This is the critical line. Without it, projects from all tenants are returned.
builder.HasQueryFilter(p => p.TenantId == _tenantContext.CurrentTenantId);
}
}