【问题标题】:How to create a multi-tenant application where the databases dont match如何创建数据库不匹配的多租户应用程序
【发布时间】:2021-09-29 14:48:58
【问题描述】:

我正在尝试提出一种方法来创建一个用作多个客户端的 CMS 的应用程序,每个客户端都有自己的数据库,但据我所知,我们在前端返回的大部分内容应该是一样。

到目前为止,我已经决定将 Reactjs 用作前端,因为它可以让我在需要的地方创建灵活性,同时还能够创建可重用的组件。

我遇到的问题是为后端提出一种方法,因为没有一个客户端共享精确的架构匹配,因此在搭建 dbcontexts 时,每个客户端都必须为每个客户端创建新的才能工作。

我最初的想法只是运行它,并在需要时为每个客户端/数据库创建一个 dbcontext,并提出一些路由逻辑,以帮助我根据每个请求定位一个上下文。然而,这可能会让我在每次获得新客户端时都编写一个新的数据层,这将使这个应用程序变得庞大而笨拙,并且需要一些杂乱的控制器或服务来管理它。

我的另一个想法是为每个客户端创建一个 API,并从前端创建一个可配置的调用以获取正确的 API,但我不确定这有多安全,而且看起来不太明智,但会离开我的后端是可维护的小块。

对这些方法中的任何一种或可能会更好的另一种方法有任何建议吗?

【问题讨论】:

    标签: .net entity-framework architecture


    【解决方案1】:

    我知道这匹马已经逃跑了(至少现在是这样),但是避免使用不同的模式会为您节省一个痛苦的世界。下一个最好的方法是为 80% 的解决方案提供一个通用架构,并仔细管理如何处理可变部分。

    就您的实际问题而言,孤立地...听起来 依赖注入 在这种情况下可能是您的朋友。

    一般架构看起来像这样。发生了一些不同的事情,让我依次解释一下。

    1. 每个客户端都有自己的数据库和相应的数据访问代码;数据访问代码的每个实例都实现相同的接口:IClientDataProvider
    2. 数据访问代码以北的所有代码都针对IClientDataProvider 进行编程。我假设您有单独的业务逻辑和 UI 层 - 但这与您的问题无关。
    3. DI(依赖注入)子系统在运行时决定加载哪个实际的数据访问代码(因此也决定加载哪个数据库)。

    这里的假设是,无论架构如何,这些差异都可以由数据访问代码处理,并使用一个一致的接口。

    接口和数据提供者设计 - 该图描述了最基本的解决方案,但它很容易扩展。例如,假设您有两个不同的概念:

    • 客户资料数据(姓名、地址、喜欢的颜色等)。
    • 客户端传输网络数据(不同客户端)。

    制作两种不同类型的接口,一种用于通用数据(配置文件数据),另一种用于处理不同数据(传输网络数据)。常见的只需要你开发一个实现,所以你只需要在必要的地方为接口编写重复的代码。

    专业提示 - 如果您还没有听说过,一定要熟悉Interface Segregation Principle (ISP),以便在您开始设计界面时使用。

    您可能会问,如果只有一种实现常见的东西,您是否需要使用接口?您不需要,您可以直接使用对象 - 但是:

    • 全面使用接口意味着架构和代码更加一致,更易于长期维护。
    • 从长远来看,就地接口使解决方案更容易更改。例如。假设您想更改数据提供者技术?或者客户的需求要求您在以前相同的领域有所不同。

    DTOs - 要获取周围的数据,创建一套完全愚蠢的对象来保存信息;系统使用这些来移动数据。例如:

    PizzaInfo info = IClientDataProvider.GetClientPizzaData(guid clientId)
    IClientDataProvider.Save(KittenInfo kitten);
    

    最简单的解决方案是制作一组所有层都使用的那些。如果您愿意,您显然可以选择对其进行更改。

    在运行时选择哪个数据提供者 - 我猜这取决于用户访问租户的方式。例如。有一些东西(可能在 DI 子系统中)通过 URL 传递,并调用加载哪个提供程序。

    hogwarts.holdencms.com = CMS.DataAccess.Clients.HogwartsDataProvider
    starwars.holdencms.com = CMS.DataAccess.Clients.StarWarsDataProvider
    thunderbirds.holdencms.com = CMS.DataAccess.Clients.ThunderBirdsDataProvider
    

    如果客户端之间的差异不能包含在一组接口中怎么办?这个答案分为两个部分:在高层次上重用相同的方法/原则,但将其用于加载不同的业务逻辑类和/或不同的 UI 小部件。第二部分,这不是我亲身体验过的领域,但我很确定大多数体面的 UI 框架都会有一些东西来帮助你做这类事情。

    【讨论】:

    • 这是一个很好的答案,感谢您花时间解释这么多。天哪,我知道同步模式会节省大量工作,不幸的是,更改模式比更改代码更敏感!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    相关资源
    最近更新 更多