ASP.NET Core应用程序中具有Entity Framework Core和SQL Server 2017的多个租户

时间:2018-06-17 07:42:42

标签: sql-server entity-framework asp.net-core entity-framework-core sql-server-2017

我有一个使用Entity Framework Core 2.1和SQL Server 2017(Web版)的ASP.NET Core 2.1应用程序。我阅读了很多如何解决多个租户的问题,但或多或​​少的答案是:

  

这取决于您的应用程序,设置。

设定:

  • 每个客户端都有一个新的IIS站点,其中包含自己的数据库配置
  • 一些表(客户端定义设置哪一个)必须在租户之间共享,例如:它有用户,组,权限,用户设置的公共表,但是对于商品,价格,事件分开......
  • 每个表都有标识列(int),这是主键
  • 所有租户具有完全相同的表结构(升级客户端时,所有租户都应更新所有表结构)
  • 我正在使用EF Core
  • 的代码优先方法

选项:

  1. 为每个客户和租户(Db名称client_tenant
  2. 分隔数据库
  3. 为每个客户端分隔数据库,并为租户使用架构(Db名称client.tenant
  4. 为每个客户提供单独的数据库,并在每个表中使用列(TenantId
  5. 详细信息:

    我知道每个选项都有缺点和优点,所以这里有关于设置的更多信息:

    • 每个客户有1个或更多(最多1000个)租户(平均约20个)
    • 客户必须在租户之间共享一些表格
    • 大约有500张桌子,其中大约10张可分享(普通)租户(需要分享的客户)
    • 最大的表每年可以产生1000万条记录

    优点/缺点正如我所见:

    1. 单独的数据库(租户单独的Db):

      • 正反
        • 安全
        • EF(迁移)
        • 完全支持表结构更改
        • 表格是透明的
      • 缺点
        • 不容易dynamically change database
        • 使用EF Core加入数据库is not supported(与下一点相关)
        • 目前没有解决方案如何解决常见表(用户,组,权限,用户设置) 1
        • 很多数据库:client1_tenant1client1_tenant2,...,client2_tenant1 ......
    2. 单独的方案(1Db,租户的单独方案):

      • 正反
        • 共享数据没有问题(我可以为普通表设置一个默认模式)
        • 安全(少于1.选项)
      • 缺点
    3. TenantId列(1个Db,1个方案):

      • 正反
      • 缺点
        • 可以有非常大的表(1个客户* 500个租户* 2000000个记录* 10年= 10年内100亿行 - 最大的客户,最大的表)
        • 安全 3
        • 潜在的性能问题
        • 难以维护(非常大的桌子 - 它们不透明)
    4. 要点:

      如果我:

      ,我应该选择哪种方法(1,2或3)
      • 正在使用EF Core
      • 需要在租户之间共享一些表格(同步应该在不到一分钟内发生)。 4
      • 可以拥有非常大的表格
      • 我有超过500个表,它们在逻辑上属于1个模块

      相关主题:(只是为了证明我做了功课并搜索重复内容)

      • 将2个表同步到不同的数据库:12
      • 多租户 - 代码EF 6(非核心)
      • 使用multiple Db schemas
      • 进行迁移
      • Same question设置不同
      • 以及更多,以便我能更好地理解问题和可能的解决方案

      参考文献:

      1 一种方式是SQL Server replication - 身份问题 每个客户端都有一些常用的表来管理有关女性租户可以查看,编辑,设置哪些列想要查看某些表的权限...

      2 不确定这是否可行。可能我应该为每个租户拨打for循环context.Database.Migrate();

      3 所有数据都属于同一个表,因此一个租户看到另一个租户数据的错误很糟糕,但并不具有破坏性。同样global filtering,这种风险最小化。

      4 我可以编写API来同步代码中的更改(某些后台线程),因为这些更改不会经常发生。

1 个答案:

答案 0 :(得分:1)

  

是的,这取决于你的申请。

我选择1.

  

一些表(客户端定义设置哪一个)必须在它们之间共享   租户,例如:它有用户,群组,权利,   用户设置,但针对优惠,价格,活动分开

如果您需要用于设置,用户管理,组,权限等的表,您应该为每个客户创建一个具有一个目的的单独数据库:用户处理 - crud,权限,组,检查等。

您需要将此信息作为声明或任何其他合适的授权系统传递。

所以我会像client1_user_management,client1_tenant1,client1_tenant2等一样创建

如果您使用声明(jwt,cookies)或任何其他方式传递群组,权利等,您将不再需要left join with EF Core over databases。如果我错了,请纠正我。

至于其他骗局:not so easy to dynamically change database;

为了避免这种类型的配置,您可以根据子域或类似的东西注入数据库:

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);
}

您可能有一个应用程序可以处理多个客户端/多个租户。识别和注入一个客户端&amp;每个请求一个租户。

接收请求:https://client1.myapp.com/tenant1 - &gt;我可以识别client1和tenant1,我可以找出数据库名称(硬编码像client1_tenant1或配置,如果你有租户管理系统)。由于我可以找出数据库名称,我将使用它来为每个请求创建一个DBContext(范围:What is the difference between services.AddTransient, service.AddScope and service.AddSingleton methods in Asp.Net Core?)。

P.S:这是基于当前信息的观点。如果可能的话,我会尝试推出这个解决方案。