Multi-tenant requires many features because the data can be separated by different tenants. So when you are accessing the database, you don't need to worry that your operation will affect other tenants.

Multi-tenancy is the ASP.NET boilerplate's most important feature and works perfectly with Domain-driven design. But how can we implement the multitenant feature with only pure Entity Framework Core?

First, create an example entity like this:

public class Blog
{
    public int Id { get; set; }
    public int TenantId { get; set; }

    public string Name { get; set; }
    public string Url { get; set; }
}

The Id of the blog will be your primary key in your database. And the TenantId represents which tenant of this blog belongs to. So the table was grouped by TenantId  multiple collections of the Blog.

Create your DBContext like this:

public class BloggingContext : DbContext
{
    private readonly int _tenantId;

    public BloggingContext(int tenantId)
    {
        _tenantId = tenantId;
    }

    public DbSet<Blog> Blogs { get; set; }
}

To configure your SQL Server connection, override the default OnConfiguring like this:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Demo.QueryFilters;Trusted_Connection=True;ConnectRetryCount=0;");
}

When the developer is trying to select blogs from the DBContext, we need to add a filter to get only blogs from the current tenant. Override the default OnModelCreating method.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().HasQueryFilter(b => EF.Property<int>(b, "TenantId") == _tenantId);
}

If the developer is inserting an item to the table, we need to help him set the TenantId.

public override int SaveChanges()
{
    ChangeTracker.DetectChanges();
    foreach (var item in ChangeTracker.Entries().Where(e => e.State == EntityState.Added && e.Metadata.GetProperties().Any(p => p.Name == "TenantId")))
    {
        item.CurrentValues["TenantId"] = _tenantId;
    }
    return base.SaveChanges();
}

Now we have a multi-tenant DBContext. With a BloggingContext, a developer can keep writing LINQ or lambda expression like he previously did and desn' need to concern about the tenant context for our context can work with that automatically.

But to get a BloggingContext there is an additional step. You need to specify your tenant'id when constructing it.

int tenantId = 3;
var dbContext = new BloggingContext(tenantId);

And you can migrate an existing project using Entity Framework Core to the multi-tenant application easily!