Reputation: 10459
I have an ASP.NET Core 2.1 application which uses Entity Framework Core 2.1 and SQL Server 2017 (Web edition). I read a lot of how to solve problem with multiple tenants, but more or less the answer is:
it depends on your application, setup.
Setup:
int
) which is the primary keyOptions:
client_tenant
)client.tenant
)TenantId
)Details:
I know every option has cons and pros, so here is more information about the setup:
Pros / cons as I see them:
separate databases (separate Db for tenant):
client1_tenant1
, client1_tenant2
, ..., client2_tenant1
...separate schemes (1Db, separate scheme for tenant):
TenantId
column (1 Db, 1 scheme):
Summary:
Which approach (1, 2 or 3) should I choose if I:
Related topics: (just to prove I did my homework and search for duplicates)
References:
1 One way is SQL Server replication - problems with identity.
Each client has some common tables to manage rights about witch tenant can see, edit, settings which columns want to see for some table ...
2 Not sure if this is even possible. Probably I should call in for
loop context.Database.Migrate();
for every tenant.
3 All data belongs to the same table, so bug where one tenant would see data of another tenant is awful but not devastating. Also with global filtering this risk is minimised.
4 I could write API to sync changes in code (some background thread), because these changes doesn't happen very often.
Upvotes: 0
Views: 1904
Reputation: 12452
Yea, it depends on your application.
I'd go with 1.
some tables (client defines on setup which one) must be shared between tenants, for example: it has common tables for users, groups, rights, user-settings, but separate for offers, prices, events
If you need tables for settings, user management, groups, rights, etc you should create a separate database per client that will have one purpose: user handling - crud, rights, groups, checks, etc.
You'll need to pass this information along as claims or any other suitable authorization system.
So I'll create like a client1_user_management, client1_tenant1, client1_tenant2, etc
If you're using claims (jwt, cookies) or any other way to pass along groups, rights, etc you won't need left join with EF Core over databases
. Correct me if I'm wrong.
As for the other con: not so easy to dynamically change database
;
In order to avoid this type of configuration, you can inject your database based on a subdomain or something like that:
public void Configure()
{
Dictionary<string, string> connStrs = new Dictionary<string, string>();
connStrs.Add("DB1", Configuration["Data:DB1Connection:ConnectionString"]);
connStrs.Add("DB2", Configuration["Data:DB2Connection:ConnectionString"]);
DbContextFactory.SetConnectionString(connStrs);
}
You'll probably have one application that will handle multiple clients/multiple tenants. It's useful to identify and inject one client & one tenant per request.
Receiving request for: https://client1.myapp.com/tenant1 -> i can identify client1 and tenant1 and i can figure out database name (hardcoded like client1_tenant1 or configured if you have a tenant management system). As i can figure out a database name, I'll use that to create a DBContext
per request (scoped: What is the difference between services.AddTransient, service.AddScope and service.AddSingleton methods in Asp.Net Core?).
P.S: This is an opinion based on current information. I'll try to push this solution if it's possible.
Upvotes: 1