首页 > 解决方案 > 在多租户应用场景中,同一模型是否可以具有不同的属性?

问题描述

我必须设计一个多租户应用程序,我需要为同一模型中的每个租户提供自定义字段。

客户 1 需要使用一些自定义字段,客户 2 需要管理同一张表中的其他字段,依此类推。

这是一个例子:同一张表(票证)有一个公共(基本)字段列表,那么每个租户应该在模型中有他的附加列:

我想先实现一个 EF Code 的 .Net Core Web 应用程序。

namespace Models.Base
{
    public class TicketBase
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public Datetime CreationDate { get; set; } 
    }
}

租户 1

namespace Models.Tenant1
{
    public class Ticket : TicketBase
    {

        public string CustomerName { get; set; }
        public Datetime DateCustomerCall { get; set; } 
    }
}

租户 2

namespace Models.Tenant2
{
    public class Ticket : TicketBase
    {

        public string AnotherDescription { get; set; }
        public Datetime AnotherDate { get; set; } 
    }
}

以这种方式设计模型是否正确,或者对于这个非常常见的问题有不同的方法?

标签: c#entity-framework-coremulti-tenant

解决方案


恕我直言,在 SaaS 中,拥有单一代码库和灵活的多租户配置/扩展是成功的关键。

要为每个租户启用自定义字段,业务模型必须具有固定的基本字段集。自定义字段必须按 entityid 和 tenantid 存储在单独的表中。

您的表格可能如下所示。首选此模型,这样拥有通用扩展表将导致可伸缩性降低,并且随着使用量的增加很快就会被数据量填充。

TicketExtn(包含按租户和实体的自定义字段的扩展表)

TicketExtn表将包含如下字段

TicketId TenantId FieldId FieldValue FieldDataType 等当我们尝试获取Ticket实体的数据时,我们还将从TicketExtn表中获取数据并在模型中设置字段。

BaseModel 将如下所示

public class ExtendedField
{
    public Guid Id { get; set; }
    public string FieldName { get; set; }
    public Guid DataTypeId { get; set; }
    /// <summary>
    /// Can also be a typed class, this is just for reference
    /// </summary>
    /// <value>The field value.</value>
    public string FieldValue { get; set; }
    /// <summary>
    /// Incase of using string for fieldvalue, the string to format the value as per the required datatype 
    /// will be provided here.
    /// </summary>
    /// <value>The field value format string.</value>
    public string FieldValueFormatString { get; set; }
}

public class BaseModel
{
    Dictionary<string, ExtendedField> ExtendedRows { get; set; }
}

public class Ticket : BaseModel
{
    public int Id { get; set; }
    public string Description { get; set; }
    public DateTime CreationDate { get; set; }
}

在您的服务层中,将有填充这些扩展行的逻辑。最好拥有用于填充扩展行的通用逻辑,以便对于任意数量的实体,可以重用此逻辑。

高温高压


推荐阅读