question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Deleting a model with a composite key bypassing multitenancy

See original GitHub issue

When deleting a multitenant entity that’s configured to use a composite key in our database migrations scripts and with the EF Core ModelBuilder isn’t respecting multitenancy.

The database constraint in our migrations script looks like: ALTER TABLE ONLY public."Examples" ADD CONSTRAINT "PK_Examples" PRIMARY KEY ("Number", "TenantId", "Username");

Our EF Core classes look like:

[MultiTenant]
public class ExampleModel 
{
    public string Username { get; set; }
    public string Number { get; set; }
}

public class TestDbContext : MultiTenantDbContext
{
    public DbSet<ExampleModel>? Examples { get; set; }

    public TestDbContext(TenantInfo tenantInfo,
        DbContextOptions options) :
        base(tenantInfo, options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<ExampleModel>().HasKey(b => new { b.Number, b.Username });
    }
}

When we delete an ExampleModel from the context, all other ExampleModels with the same Username and Number are deleted as well, even with different TenantIds.

Should Finbuckle be adding the TenantId to the composite key? Is there a way we can add it as part of the model builder such that the call to modelBuilder mirrors our database constraints? Is there some other solution?

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
AndrewTriesToCodecommented, Feb 24, 2022

Alright I removed the generator and filed a bug with the efcore team. They said only on “adding” a tracked entity will it pick up a shadow key property. I voted on an issue to expand that to any method which attaches an entity.

The best option here is to do exactly what you did – or to use the TenantNotSetMode which as of the latest release should work as intended with the generator removed.

Thanks!

1reaction
AndrewTriesToCodecommented, Feb 16, 2022

Ok, having dug in I can explain some parts but not all. Thank you for isolating the behavior so well.

  • first of all only .NET 6 has a passing test. I need to look at the earlier versions closer.
  • HandleNoTenantIdInCompositeKeyAndShadowTenantIdInModel and HandleNoTenantIdInCompositeKeyAndExplicitTenantIdInModel I would expect to fail because EFCore doesn’t even know TenantId is intended to be part of the key. Finbuckle leans heavily on global query filters for tenant data isolation and unfortunately they don’t apply to delete statements. EFCore seems to use the key columns it knows about to generate delete statements hence wiping the records for all tenants.
  • For the other 2 tests, HandleTenantIdInCompositeKeyAndExplicitTenantIdInModel works as expected and I recommend you explicitly add TenantId to models if within your control – shadow properties just cause so many headaches. For HandleAdjustedCompositeKeyAndShadowTenantIdInModel this should work but I think we might be hitting this bug so I posed a question there.
  • In all of these cases the TenantNotSetMode is the default of throw so it should actually prevent the save attempt. This makes me realize the value generator for TenantId is masking this intended behavior. I’ll have to take a closer look at this.

I hope this help and thanks for all the details.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Hibernate composite key and overlapping field
As described here, you can bypass the validation by using @JoinColumnOrFormula for the column id_tenant.
Read more >
Multi-schema, multi-tenant databases - data isolation ...
I would suggest removing it or explaining in the question the express purpose ... Composite Primary Key in multi-tenant SQL Server database.
Read more >
COMPOSITE KEYS FOR MULTI-TENANT NON- ...
A user request is received to define a composite key for a data object. A metadata model is generated representing the data object, ......
Read more >
Multi-tenant data isolation with PostgreSQL Row Level ...
In this design, all tenant data sits side-by-side, but each table or view contains a partitioning key (usually the tenant identifier), which you ......
Read more >
How Hibernate Almost Ruined My Career
You write down migration scripts, then you update the entity model along with the Hibernate mappings, so it keeps in sync with the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found