In a multi-tenant ASP.NET MVC application based on Rob Conery's MVC Storefront, should I be filtering the tenant's data in the repository or the service layer?
public interface IJobRepository
{
IQueryable<Job> GetJobs(short tenantId);
}
public interface IJobService
{
IList<Job> GetJobs(short tenantId);
}
My gut-feeling says to do it in the service layer (option 2), but it could be argued that each tenant should in essence have their own "virtual repository," (option 1) where this responsibility lies with the repository.
I tried the proposed idea of filtering at the repository, but the problem is that my application provides the tenant context (via sub-domain) and only interacts with the service layer. Passing the context all the way to the repository layer is a mission.
So instead I have opted to filter my data at the service layer. I feel that the repository should represent all data physically available in the repository with appropriate filters for retrieving tenant-specific data, to be used by the service layer.
I ended up abandoning this approach due to the unnecessary complexities. See my answer below.
@FreshCode, we do it in the repository, and we do not pass the tenant as a parameter. We use the following approach:
public IQueryable<Job> GetJobs()
{
return _db.Jobs.Where(j=>j.TenantId == Context.TenantId);
}
The context is a dependency the repository has and that is created in the BeginRequest where you determine the tenant based on the url for example.
I think in this way it's pretty transparent and you can avoid the tenantId
parameter which may become a little bit disturbing.
Regards.
Update: Not going with a multi-tenant approach cost me hundreds of hours in technical debt. Four years down the line, I wish I took the time to implement a clean tenant approach first. Don't make the same mistake!
I ended up stripping out all multi-tenant code in favour of using separate applications and databases for each tenant. In my case I have few tenants that do not change often, so I can do this.
All my controllers, membership providers, role providers, services and repositories were gravitating toward duplicate .WithTenantID(...)
code all over the place, which made me realize that I didn't really need one Users
table to access data that is specific to one tenant 99% of the time, so using separate applications just makes more sense and makes everything so much simpler.
Thanks for your answers - they made me realize that I needed a redesign.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With