在 .NET 中,您将如何允许多租户 SaaS 应用程序的租户向模型的实体任意添加属性?

发布于 2024-07-07 11:45:38 字数 1726 浏览 6 评论 0原文

因此,我们正在构建一个多租户系统作为服务运行。 我们从头开始。 我们遵循DDD; 该域(目前)有大约 20 个实体,以后还会有更多。 它由我们托管,地理上是冗余的(除了 SQL 查询之外,所有内容都是 n+1;-)),并且设计灵活(好吧,最后一个是我们自己的要求,而不是业务',尽管他们希望我们能够当然可以根据需要轻松更改)。 我们基于 .NET,并将使用关系数据库作为我们的后备存储。 我们不反对使用开源工具和库(完全)。

业务必须具备的功能之一是系统租户可以扩展某些实体。 例如,客户端 A 可能希望实体 Foo 具有 Title 和 Abstract 属性,而客户端 B 可能希望实体 Foo 具有 Publish Date 和 Directed-By 属性,而不是 Title Abstract 属性。

也可能是这样的情况,它应该为有需要的租户支持多种语言的数据 - 例如,一个租户可能有兴趣将其整个帐户翻译成两种(或更多)语言; “静态”字符串以及作为数据附加到实体的字符串。

所以。 任意数量的字段(在一些公共基线之上;所有租户都会获得有关这些实体的某些信息),可由客户端定义(他们也可以定义数据类型)。 翻译数据的可能性(无需复制实体 - 如,无需用英语设置一组,然后用法语设置同一组)。 强类型、可搜索、可查询的后备存储也是如此(因此,XML 字段中没有额外的内容,除非有办法使其成为强类型和可搜索的)。 高性能(但作为次要要求;该功能非常重要,需要在必要时购买硬件)。

数据量? 在我们当前的系统中,“普通”客户端有数百个实体,“大”客户端有数千个实体。 请求通常会过滤这些列表以将其显示在 10-200 之间,并且最常见的事情可能涉及六个实体(在新系统中,应该是可扩展的)。

其他要点? 每个实体都与拥有它的租户有直接链接。

在 .NET 领域如何解决这一问题? 有人建议我们将实体放入 IoC 容器中,并在运行时将它们动态地组合在一起 - 但如何将其映射到关系数据库呢?

我还记得读过 Ayende 的帖子 在很久以前就使用 Lucene.NET 来解决这个问题,听起来不错,但目前我们还没有使用 Lucene.NET 或 nHibernate 的任何经验。 (我们目前将使用 Linq2Sql 作为我们的 ORM,但如果我们需要更改它来支持这一点,坦率地说,我个人会很高兴)。

我阅读了这个 Castle 开发列表帖子,其中链接自 Ayende,看起来 nHibernate 有一种叫做 IUserType 的东西可能会有所帮助 - 我想知道我们是否可以应用它,为每个租户提取适当的 IoC? 因此,每个租户每个可扩展实体一个 IUserType,并将数据本身存储在 SQL Server(我们最有可能的 RDBMS)内的 XML 列中。

最后,我刚刚读到了一项关于动态更改每个租户每个实体的数据库表的建议 - 但这听起来很漂亮......老实说,令人担忧! 我的意思是,它可以工作,但向租户(他们可能不太懂技术)提供这样做的能力听起来并不是一个好主意。 我想它可能仅限于管理员员工......

So, we're building a multi-tenant system to run as a service. We're starting from the ground up. We're following DDD; the domain has (at the moment) ~20 entities in it, and later there will be more. It is to be hosted by us, geographically redundant (n+1 of everything except SQL queries ;-) ), and of flexible design (well, that last is our own requirement, not the business', though they want us to be able to change it easily on demand of course). We're .NET based, and will be using a relational database for our backing store. We're not against using open-source tools and libraries (at all).

One of the must-have features from the business is that certain entities be extensible by the tenants of the system. For example, client A may want entity Foo to have Title and Abstract properties, whereas client B may want entity Foo to have Publish Date and Directed-By properties - and not Title Abstract.

It may also be the case that it should support data in multiple languages for tenants that want this - for example, one tenant may be interested in translating their whole account into two (or more) languages; both the "static" strings, and the strings attached to the entities as data.

So. Arbitrary number of fields (on top of some common baseline; there are certain things about these entities that all tenants will get), definable by the client (where they can define the data-type too). Possibility of translation of the data (without duplicating the entities - as in, without setting up one set in English, and then setting up the same set in French). Strongly typed, searchable, queryable backing storage, too (so, no extra-stuff-goes-in-an-XML-field, unless there's a way for it to come out strongly-typed and searchable). Performant (but as a secondary requirement; the feature is important enough to buy hardware for if necessary).

Data volumes? In our current system, an "average" client has hundreds of entities, a "big" client has thousands of entities. Requests will usually filter those lists for display to between 10-200ish, and the most common thing to want to do will involve maybe half-a-dozen entities (that in the new system, should be extensible).

Other points? Each Entity has a direct link to the tenant that owns it.

How does one go about this, in .NET-land? It's been suggested that we chuck our entities into an IoC container, and glob them together on the fly at run-time - but how does one map that to a relational database?

I also remember reading Ayende's post on this with Lucene.NET from some significant time ago that sounds good, but we haven't got any experience with Lucene.NET or nHibernate at present. (We're currently going to use Linq2Sql for our ORM but if we need to change that to support this, I'd personally be happy, frankly).

I read this Castle dev list thread which is linked from Ayende, and it seems like nHibernate has something called an IUserType that might help - I wonder whether we might apply that, pulling the appropriate one our of IoC for each tenant? So one IUserType per tenant per extensible-entity, and store the data itself in an XML column inside of SQL Server (our most likely RDBMS).

Lastly, I've just read one suggestion around dynamically changing a DB-table per entity per tenant - but this sounds pretty... Fraught, honestly! I mean, it could work, but it sounds like not such a great idea to give out the ability to do this to tenants (who may be less than tech-savvy). I suppose it could restricted to administrator-employees only...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笑叹一世浮沉 2024-07-14 11:45:38

Take a look at Ayende's series of posts about multi-tenancy.
He analyzes several approaches to the issue of extensibility.

亢潮 2024-07-14 11:45:38

有多种方法可以实现这一目标,但多租户的问题比数据模型更深入。 我讨厌插入产品,但请查看我工作的公司的 SaaSGridApprenda。我们是一个云操作系统,允许您编写单租户 SOA 应用程序(可以随意使用 NHibernate 进行数据访问),自动将多租户注入您的应用程序。 当您发布应用程序时,您可以执行诸如选择数据模型(隔离数据库或共享)之类的操作,SaaSGrid 将进行相应部署,并且您的应用程序将无需更改任何代码即可运行 - 只需像为单个租户编写代码一样!

There are a variety of ways to accomplish it, but the issues of multi-tenancy go deeper than just the data model. I hate to be plugging product, but check out SaaSGrid by my the company I work at, Apprenda.We're a cloud operating system that allows you to write single tenant SOA apps (feel free to use NHibernate for data access) that automatically injects multi-tenancy into your app. When you publish your app, you can do things like choose a data model (isolated database or shared) and SaaSGrid will deploy accordingly and your app will run without any code changes - just write code as if it were for a single tenant!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文